/*
 * tuongky.c
 *
 *  Created on: Mar 27, 2013
 *      Author: locpm
 */

#include <stdio.h>
#include <sys/timeb.h>
#include <string.h>
#include <signal.h>

#define MAX_CMD_BUFF 256

// Number of moves that we can store (all plies)
#define MAX_MOV_BUFF 4096

// Search depth
#define MAX_PLY 64

// Number of moves in the (game + search) line that we can store
#define MAX_GAME_LINE 1024

typedef unsigned char BOOL;

typedef unsigned int U32;

typedef unsigned long long U64;

typedef struct {
	U32 bb[3];
} BITBOARD;

typedef struct
{
	// from (7 bits) The from square identified by a number from 0 to 89, using 7 bits
	// tosq (7 bits) The to square identified by a number from 0 to 89, using 7 bits
	// piec (4 bits) The moving piece that identified by a number from 0 to 15, using 4 bits
	// capt (4 bits) The captured piece that identified by a number from 0 to 15, using 4 bits
	// This int variable is 32-bit length, we use 7 + 7 + 4 + 4 = 22 bits, the last 10 bits is ignored
	unsigned int moveInt;
} MOVE;

typedef struct
{
	MOVE move;
} GAMELINERECORD;

typedef struct
{
	U64 startTime;
	U64 stopTime;
	U64 currentTime;
	U64 stopTimeDelta;
	struct timeb startBuffer;
	struct timeb stopBuffer;
	struct timeb currentBuffer;
	BOOL running;
} TIMER;

typedef struct
{
	// bitboards to store a chess position
	BITBOARD whiteKing, whiteAdvisors, whiteElephants, whiteRooks, whiteCannons, whiteHorses, whitePawns;
	BITBOARD blackKing, blackAdvisors, blackElephants, blackRooks, blackCannons, blackHorses, blackPawns;
	BITBOARD whitePieces, blackPieces, occupiedSquares;

	// incrementally updated, this array is usefull if we want to
	// probe what kind of piece is on a particular square.
	int square[90];

	// WHITE_MOVE or BLACK_MOVE
	unsigned char nextMove;

	// only used for displaying the board. TRUE or FALSE.
	BOOL viewRotated;

	// storing moves:
	// all generated moves of the current search tree are stored in this array.
	MOVE moveBuffer[MAX_MOV_BUFF];

	// this arrays keeps track of which moves belong to which ply
	int moveBufLen[MAX_PLY];

	GAMELINERECORD gameLine[MAX_GAME_LINE];

	// index for gameLine
	int endOfGame;

	// index for gameLine
	int endOfSearch;

	// Search depth
	int searchDepth;

	// search variables:
	int triangularLength[MAX_PLY];
	MOVE triangularArray[MAX_PLY][MAX_PLY];

	U64 msStart, msStop;
	U64 inodes;

	TIMER timer;

	int lastPVLength;
	MOVE lastPV[MAX_PLY];
	unsigned int whiteHeuristics[90][90];
	unsigned int blackHeuristics[90][90];
	BOOL followpv;

	int material;

	U64 countdown;
	U64 maxTime;
	BOOL timedout;
} BOARD;

#if defined(_WIN32)
#define PRINTF_INT64_MODIFIER "I64"
#else
#define PRINTF_INT64_MODIFIER "ll"
#endif

#define WINGLET_DEBUG_WINBOARD

void initData();


void initBoard(BOARD* m_board);
void displayBoard(BOARD m_board);
void initBoardFromSquares(BOARD* m_board, int m_square[90], unsigned char m_nextMove);
int eval();
MOVE think();
int minimax(int ply, int depth);
int alphabeta(int ply, int depth, int alpha, int beta);
int alphabetapvs(int ply, int depth, int alpha, int beta);

BOOL isEndOfgame(int *legalmoves, MOVE *singlemove);

void rememberPV();
void selectmove(int ply, int i, int depth, BOOL followpv);

char CMD_BUFF[MAX_CMD_BUFF];
unsigned int CMD_BUFF_COUNT = 0;

// Identifier of next move:
const BOOL TRUE = 1;
const BOOL FALSE = 0;

// Identifier of next move:
const unsigned char WHITE_MOVE = 0;
const unsigned char BLACK_MOVE = 1;

BOARD board;

/*
	RANKS:
	   9 |       81   82   83   84   85   86   87   88    89    (MSB,
	   8 |       72   73   74   75   76   77   78   79    80    left)
	   7 |       63   64   65   66   67   68   69   70    71
	   6 |       54   55   56   57   58   59   60   51    62
	   5 |       45   46   47   48   49   50   51   52    53
	   4 |       36   37   38   39   40   41   42   43    44
	   3 |       27   28   29   30   31   32   33   34    35
	   2 |       18   19   20   21   22   23   24   25    26
	   1 |        9   10   11   12   13   14   15   16    17
	   0 | (LSB,  0    1    2    3    4    5    6    7    8
		 |  right)
		  ----------------------------------------------------
	 FILES:       a    b    c    d    e    f    g    h    i
 */

const unsigned int A0 = 0;
const unsigned int A1 = 9;
const unsigned int A2 = 18;
const unsigned int A3 = 27;
const unsigned int A4 = 36;
const unsigned int A5 = 45;
const unsigned int A6 = 54;
const unsigned int A7 = 63;
const unsigned int A8 = 72;
const unsigned int A9 = 81;

const unsigned int B0 = 1;
const unsigned int B1 = 10;
const unsigned int B2 = 19;
const unsigned int B3 = 28;
const unsigned int B4 = 37;
const unsigned int B5 = 46;
const unsigned int B6 = 55;
const unsigned int B7 = 64;
const unsigned int B8 = 73;
const unsigned int B9 = 82;

const unsigned int C0 = 2;
const unsigned int C1 = 11;
const unsigned int C2 = 20;
const unsigned int C3 = 29;
const unsigned int C4 = 38;
const unsigned int C5 = 47;
const unsigned int C6 = 56;
const unsigned int C7 = 65;
const unsigned int C8 = 74;
const unsigned int C9 = 83;

const unsigned int D0 = 3;
const unsigned int D1 = 12;
const unsigned int D2 = 21;
const unsigned int D3 = 30;
const unsigned int D4 = 39;
const unsigned int D5 = 48;
const unsigned int D6 = 57;
const unsigned int D7 = 66;
const unsigned int D8 = 75;
const unsigned int D9 = 84;

const unsigned int E0 = 4;
const unsigned int E1 = 13;
const unsigned int E2 = 22;
const unsigned int E3 = 31;
const unsigned int E4 = 40;
const unsigned int E5 = 49;
const unsigned int E6 = 58;
const unsigned int E7 = 67;
const unsigned int E8 = 76;
const unsigned int E9 = 85;

const unsigned int F0 = 5;
const unsigned int F1 = 14;
const unsigned int F2 = 23;
const unsigned int F3 = 32;
const unsigned int F4 = 41;
const unsigned int F5 = 50;
const unsigned int F6 = 59;
const unsigned int F7 = 68;
const unsigned int F8 = 77;
const unsigned int F9 = 86;

const unsigned int G0 = 6;
const unsigned int G1 = 15;
const unsigned int G2 = 24;
const unsigned int G3 = 33;
const unsigned int G4 = 42;
const unsigned int G5 = 51;
const unsigned int G6 = 60;
const unsigned int G7 = 69;
const unsigned int G8 = 78;
const unsigned int G9 = 87;

const unsigned int H0 = 7;
const unsigned int H1 = 16;
const unsigned int H2 = 25;
const unsigned int H3 = 34;
const unsigned int H4 = 43;
const unsigned int H5 = 52;
const unsigned int H6 = 61;
const unsigned int H7 = 70;
const unsigned int H8 = 79;
const unsigned int H9 = 88;

const unsigned int I0 = 8;
const unsigned int I1 = 17;
const unsigned int I2 = 26;
const unsigned int I3 = 35;
const unsigned int I4 = 44;
const unsigned int I5 = 53;
const unsigned int I6 = 62;
const unsigned int I7 = 71;
const unsigned int I8 = 80;
const unsigned int I9 = 89;

const char* SQUARENAME[90] = {"a0","b0","c0","d0","e0","f0","g0","h0", "i0",
		"a1","b1","c1","d1","e1","f1","g1","h1", "i1",
		"a2","b2","c2","d2","e2","f2","g2","h2", "i2",
		"a3","b3","c3","d3","e3","f3","g3","h3", "i3",
		"a4","b4","c4","d4","e4","f4","g4","h4", "i4",
		"a5","b5","c5","d5","e5","f5","g5","h5", "i5",
		"a6","b6","c6","d6","e6","f6","g6","h6", "i6",
		"a7","b7","c7","d7","e7","f7","g7","h7", "i7",
		"a8","b8","c8","d8","e8","f8","g8","h8", "i8",
		"a9","b9","c9","d9","e9","f9","g9","h9", "i9"};

// white = 0xxx, black = 1xxx
const unsigned char EMPTY = 0;                //  0000
const unsigned char WHITE_PAWN = 1;           //  0001
const unsigned char WHITE_KING = 2;           //  0010
const unsigned char WHITE_ADVISOR = 3;        //  0011
const unsigned char WHITE_ELEPHANT =  4;      //  0100
const unsigned char WHITE_ROOK = 5;           //  0101
const unsigned char WHITE_CANNON = 6;         //  0110
const unsigned char WHITE_HORSE = 7;          //  0111
const unsigned char BLACK_PAWN = 8;           //  1000
const unsigned char BLACK_KING = 9;           //  1001
const unsigned char BLACK_ADVISOR = 10;       //  1010
const unsigned char BLACK_ELEPHANT = 11;      //  1011
const unsigned char BLACK_ROOK = 12;          //  1100
const unsigned char BLACK_CANNON = 13;        //  1101
const unsigned char BLACK_HORSE = 14;         //  1110

const char PIECENAMES[15] = {'.','P','K','A','E','R','C','H',
		'p','k','a','e','r','c','h'};

// BITSET has only one bit set
U32 BITSET[30];

// BITBOARDSET has only one bit set
BITBOARD BITBOARDSET[90];

// BOARDINDEX is used to translate [file][rank] to [square]
unsigned int BOARDINDEX[9][10];

// Square to bitboard index
const unsigned int SQUARE_TO_BITBOARD_INDEX[90] = {
		0, 0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 0, 0, 0, 0, 0, 0,
		0, 0, 0, 1, 1, 1, 1, 1, 1,
		1, 1, 1, 1, 1, 1, 1, 1, 1,
		1, 1, 1, 1, 1, 1, 1, 1, 1,
		1, 1, 1, 1, 1, 1, 2, 2, 2,
		2, 2, 2, 2, 2, 2, 2, 2, 2,
		2, 2, 2, 2, 2, 2, 2, 2, 2,
		2, 2, 2, 2, 2, 2, 2, 2, 2
};

// Square to bitset index
const unsigned int SQUARE_TO_BITSET_INDEX[90] = {
		0,  1,  2,  3,  4,  5,  6,  7,  8,
		9, 10, 11, 12, 13, 14, 15, 16, 17,
		18, 19, 20, 21, 22, 23, 24, 25, 26,
		27, 28, 29,  0,  1,  2,  3,  4,  5,
		6,  7,  8,  9, 10, 11, 12, 13, 14,
		15, 16, 17, 18, 19, 20, 21, 22, 23,
		24, 25, 26, 27, 28, 29,  0,  1,  2,
		3,  4,  5,  6,  7,  8,  9, 10, 11,
		12, 13, 14, 15, 16, 17, 18, 19, 20,
		21, 22, 23, 24, 25, 26, 27, 28, 29,
};

// FILES is used to translate [square] [file]
const unsigned int FILES[90] = {
		0, 1, 2, 3, 4, 5, 6, 7, 8,
		0, 1, 2, 3, 4, 5, 6, 7, 8,
		0, 1, 2, 3, 4, 5, 6, 7, 8,
		0, 1, 2, 3, 4, 5, 6, 7, 8,
		0, 1, 2, 3, 4, 5, 6, 7, 8,
		0, 1, 2, 3, 4, 5, 6, 7, 8,
		0, 1, 2, 3, 4, 5, 6, 7, 8,
		0, 1, 2, 3, 4, 5, 6, 7, 8,
		0, 1, 2, 3, 4, 5, 6, 7, 8,
		0, 1, 2, 3, 4, 5, 6, 7, 8
};

// RANKS is used to translate [square] [rank]
const unsigned int RANKS[90] = {
		0, 0, 0, 0, 0, 0, 0, 0, 0,
		1, 1, 1, 1, 1, 1, 1, 1, 1,
		2, 2, 2, 2, 2, 2, 2, 2, 2,
		3, 3, 3, 3, 3, 3, 3, 3, 3,
		4, 4, 4, 4, 4, 4, 4, 4, 4,
		5, 5, 5, 5, 5, 5, 5, 5, 5,
		6, 6, 6, 6, 6, 6, 6, 6, 6,
		7, 7, 7, 7, 7, 7, 7, 7, 7,
		8, 8, 8, 8, 8, 8, 8, 8, 8,
		9, 9, 9, 9, 9, 9, 9, 9, 9
};

const unsigned int INDEX32[32] = {
		0,  1, 28,  2, 29, 14, 24, 3,
		30, 22, 20, 15, 25, 17,  4, 8,
		31, 27, 13, 23, 21, 19, 16, 7,
		26, 12, 18,  6, 11,  5, 10, 9
};

const unsigned int DEBRUIJN32 = 0x077CB531;

// Attack tables:
BITBOARD HORSE_ATTACKS[90][4];
BITBOARD HORSE_OBSTRUCTS[90][4];
BITBOARD ELEPHANT_ATTACKS[90][4];
BITBOARD ELEPHANT_OBSTRUCTS[90][4];
BITBOARD ADVISOR_ATTACKS[90];
BITBOARD KING_ATTACKS[90];
BITBOARD WHITE_PAWN_ATTACKS[90];
BITBOARD BLACK_PAWN_ATTACKS[90];

BITBOARD ATTACKS_RIGHT[90];
BITBOARD ATTACKS_TOP[90];
BITBOARD ATTACKS_LEFT[90];
BITBOARD ATTACKS_BOTTOM[90];

const int PAWN_VALUE = 66;
const int KING_VALUE = 6000;
const int ADVISOR_VALUE = 133;
const int ELEPHANT_VALUE = 166;
const int ROOK_VALUE = 600;
const int CANNON_VALUE = 300;
const int HORSE_VALUE = 266;

// Search parameters start here:
const int LARGE_NUMBER = 6000 + 1; // KING_VALUE + 1
const int CHECKMATESCORE = 6000; // KING_VALUE
MOVE NOMOVE;

// Default search depth
const int DEFAULT_SEARCH_DEPTH = 16;

// Default search time in milliseconds
const int DEFAULT_SEARCH_TIME = 180000;

// This constant is used in notBitBoard(BITBOARD) function
// In binary: 0011 1111 1111 1111 1111 1111 1111 1111
// The first two bits are not used in BITBOARD struct
const U32 LAST_THIRTY_BIT_SET = 0x3FFFFFFF;

// peek interval in searched node units
int UPDATEINTERVAL = 100000;
// don't start a new iteration if STOPFRAC fraction of our max search time has passed:
double STOPFRAC = 0.7;
// keep track of stdout (writing to a file or to the console):
int TOCONSOLE;



char INIFILE[80];
char PATHNAME[80];


// Winboard constants & variables:
BOOL XB_MODE;
BOOL XB_PONDER;
BOOL XB_POST;
BOOL XB_DO_PENDING;
BOOL XB_NO_TIME_LIMIT;
unsigned char XB_NONE = 2;
unsigned char XB_ANALYZE = 3;
unsigned char XB_COMPUTER_SIDE;
int XB_MIN;
int XB_SEC;
int XB_MPS;
int XB_INC;
int XB_OTIM;
int XB_CTIM;


void setFrom(MOVE* m_move, unsigned int m_from);
void setTosq(MOVE* m_move, unsigned int m_tosq);
void setPiec(MOVE* m_move, unsigned int m_piec);
void setCapt(MOVE* m_move, unsigned int m_capt);

unsigned int getFrom(MOVE m_move);
unsigned int getTosq(MOVE m_move);
unsigned int getPiec(MOVE m_move);
unsigned int getCapt(MOVE m_move);

void clear(MOVE* m_move);





BOOL doCommand(const char* buf);
void readCommands();
void commands();
BOOL doIniCommand(const char *buf);
void displayBitBoard(BITBOARD bitboard);

/* setting all bits to 0 */
void clearBitBoard(BITBOARD* bitboard);

/* Logical operations like taking the AND of two bitboards */
BITBOARD andTwoBitBoards(BITBOARD bitboard1, BITBOARD bitboard2);

/* Logical operations like taking the OR of two bitboards */
BITBOARD orTwoBitBoards(BITBOARD bitboard1, BITBOARD bitboard2);

/* Logical operations like taking the XOR of two bitboards */
BITBOARD xorTwoBitBoards(BITBOARD bitboard1, BITBOARD bitboard2);

/* Logical operations like taking the AND of numBB bitboards */
BITBOARD andMultipleBitBoards(BITBOARD bitboard[], int numBB);

/* Logical operations like taking the OR of numBB bitboards */
BITBOARD orMultipleBitBoards(BITBOARD[], int numBB);

/* Logical operations like taking the XOR of numBB bitboards */
BITBOARD xorMultipleBitBoards(BITBOARD bitboard[], int numBB);

/* Logical operations like taking the NOT of a bitboard */
BITBOARD notBitBoard(BITBOARD bitboard);

/* Check if bitboard has only zero bits */
int isAllZeroBit(BITBOARD bitboard);

/*
 * Find the least significant index or position of the bits set to one in the U32 word
 * Note: this algorithm does not handle the zero input
 * See http://en.wikipedia.org/wiki/Find_first_set
 *
 * Don't use this if u32 = 0
 */
U32 findFirstOne(U32 u32);

/*
 * Find the most significant index or position of the bits set to one in the U32 word
 * Note: this algorithm does not handle the zero input
 * See http://en.wikipedia.org/wiki/Most_significant_bit
 *
 * Don't use this if u32 = 0
 */
U32 findLastOne(U32 u32);

/**
 * Don't use this if bitboard = 0
 */
U32 findFirstOneInBitBoard(BITBOARD bitboard);

/**
 * Don't use this if bitboard = 0
 */
U32 findLastOneInBitBoard(BITBOARD bitboard);

void displayMove(MOVE move);
unsigned int movegen(unsigned int index);
unsigned int captgen(unsigned int index);

// makeMove function used for "move <moveText>" command
void makeMove(MOVE move);

// unMakeMove function used for "undo" command
void unMakeMove(MOVE move);

BOOL isValidTextMove(char *userMove, MOVE *move);

BOOL isOtherKingAttacked();
BOOL isOwnKingAttacked();

BOOL isAttacked(BITBOARD targetBitBoard, unsigned char fromSide);

void makeCapture(unsigned int captured, unsigned int to);
void unMakeCapture(unsigned int captured, unsigned int to);

BOOL isTwoKingsFaceToFace();

unsigned int bitCnt(U32 u32);
unsigned int bitCntBB(BITBOARD bitboard);

void displaySearchStats(int mode, int depth, int score);

U64 perft(int fly, int depth);




// start the timer
void initTimer(TIMER *timer);

// stop the timer
void stopTimer(TIMER *timer);

// reset the timer
void resetTimer(TIMER *timer);

// display time in seconds with 2 decimals
void displayTimer(TIMER *timer);

// display time in hh:mm:ss.dd
void displayTimerHMS(TIMER *timer);

// return time in milliseconds
U64 getMSTimer(TIMER *timer);

// return system time
U64 getSysMSTimer(TIMER *timer);

int qsearch(int ply, int alpha, int beta);

void mstostring(U64 dt, char *timestring);
void readClockAndInput();


void readIniFile();


int main(int argc, char *argv[])
{
	signal(SIGINT, SIG_IGN);
	setbuf(stdin, NULL);


	initData();
	//	readCommands();


	int i;
	// read the initialization file:
	strcpy(PATHNAME, argv[0]);
	strcpy(INIFILE, "chessfox.ini");  // default name
	// check command-line to see if we need to use another ini-file:
	// usage: "chessfox.exe i=somefile.ini"
	for (i = 1; i < argc; i++)
	{
		if (!strncmp(argv[i], "i=", 2)) sscanf(argv[i]+2,"%s", INIFILE);
	}
	readIniFile();

	printf("'help' displays a list of commands\n");

	commands();

	return 0;
}


void displayBitBoard(BITBOARD bitboard)
{
	int square, rank, file;
	char boardc[90];

	for (square = 0; square < 90; square++)
	{
		if (isAllZeroBit(andTwoBitBoards(bitboard, BITBOARDSET[89 - square])))
			boardc[square] = '.';
		else
			boardc[square] = '1';
		printf("%c", boardc[square]);
	}

	printf("\n");
	printf("bb[0] = %u; bb[1] = %u; bb[2] = %u\n", bitboard.bb[0], bitboard.bb[1], bitboard.bb[2]);
	for (rank = 0; rank < 10; rank++)
	{
		for (file = 8; file >= 0; file--)
		{
			printf("%c", boardc[BOARDINDEX[file][rank]]);
		}
		printf("\n");
	}
	printf("\n");
}

/* setting all bits to 0 */
void clearBitBoard(BITBOARD* bitboard)
{
	bitboard->bb[0] = 0;
	bitboard->bb[1] = 0;
	bitboard->bb[2] = 0;
}

/* Logical operations like taking the AND of two bitboards */
BITBOARD andTwoBitBoards(BITBOARD bitboard1, BITBOARD bitboard2)
{
	BITBOARD result;

	result.bb[0] = bitboard1.bb[0] & bitboard2.bb[0];
	result.bb[1] = bitboard1.bb[1] & bitboard2.bb[1];
	result.bb[2] = bitboard1.bb[2] & bitboard2.bb[2];

	return result;
}

/* Logical operations like taking the AND of two bitboards */
BITBOARD orTwoBitBoards(BITBOARD bitboard1, BITBOARD bitboard2)
{
	BITBOARD result;

	result.bb[0] = bitboard1.bb[0] | bitboard2.bb[0];
	result.bb[1] = bitboard1.bb[1] | bitboard2.bb[1];
	result.bb[2] = bitboard1.bb[2] | bitboard2.bb[2];

	return result;
}

/* Logical operations like taking the AND of two bitboards */
BITBOARD xorTwoBitBoards(BITBOARD bitboard1, BITBOARD bitboard2)
{
	BITBOARD result;

	result.bb[0] = bitboard1.bb[0] ^ bitboard2.bb[0];
	result.bb[1] = bitboard1.bb[1] ^ bitboard2.bb[1];
	result.bb[2] = bitboard1.bb[2] ^ bitboard2.bb[2];

	return result;
}

/* Logical operations like taking the AND of numBB bitboards */
BITBOARD andMultipleBitBoards(BITBOARD bitboard[], int numBB)
{
	BITBOARD result = bitboard[0];

	int i;
	for (i = 1; i < numBB; i++)
	{
		result.bb[0] &= bitboard[i].bb[0];
		result.bb[1] &= bitboard[i].bb[1];
		result.bb[2] &= bitboard[i].bb[2];
	}

	return result;
}

/* Logical operations like taking the OR of numBB bitboards */
BITBOARD orMultipleBitBoards(BITBOARD bitboard[], int numBB)
{
	BITBOARD result = bitboard[0];

	int i;
	for (i = 1; i < numBB; i++)
	{
		result.bb[0] |= bitboard[i].bb[0];
		result.bb[1] |= bitboard[i].bb[1];
		result.bb[2] |= bitboard[i].bb[2];
	}

	return result;
}

/* Logical operations like taking the XOR of numBB bitboards */
BITBOARD xorMultipleBitBoards(BITBOARD bitboard[], int numBB)
{
	BITBOARD result = bitboard[0];

	int i;
	for (i = 1; i < numBB; i++)
	{
		result.bb[0] ^= bitboard[i].bb[0];
		result.bb[1] ^= bitboard[i].bb[1];
		result.bb[2] ^= bitboard[i].bb[2];
	}

	return result;
}

/* Logical operations like taking the NOT of a bitboard */
BITBOARD notBitBoard(BITBOARD bitboard)
{
	BITBOARD result = bitboard;

	result.bb[0] = ~bitboard.bb[0];
	result.bb[1] = ~bitboard.bb[1];
	result.bb[2] = ~bitboard.bb[2];

	result.bb[0] &= LAST_THIRTY_BIT_SET;
	result.bb[1] &= LAST_THIRTY_BIT_SET;
	result.bb[2] &= LAST_THIRTY_BIT_SET;

	return result;
}

/* Check if bitboard has only zero bits */
int isAllZeroBit(BITBOARD bitboard)
{
	return (bitboard.bb[0] == 0) && (bitboard.bb[1] == 0) && (bitboard.bb[2] == 0);
}

/*
 * Find the least significant index or position of the bits set to one in the U32 word
 * Note: this algorithm does not handle the zero input
 * See http://en.wikipedia.org/wiki/Find_first_set
 *
 * Don't use this if u32 = 0
 */
U32 findFirstOne(U32 u32)
{
	return INDEX32[((u32 & (-u32)) * DEBRUIJN32) >> 27];
}

/*
 * Find the most significant index or position of the bits set to one in the U32 word
 * Note: this algorithm does not handle the zero input
 * See http://en.wikipedia.org/wiki/Most_significant_bit
 *
 * Don't use this if u32 = 0
 */
U32 findLastOne(U32 u32)
{
	u32 |= u32 >> 1;
	u32 |= u32 >> 2;
	u32 |= u32 >> 4;
	u32 |= u32 >> 8;
	u32 |= u32 >> 16;
	u32 = (u32 >> 1) + 1;

	return INDEX32[(u32 * DEBRUIJN32) >> 27];
}

/**
 * Don't use this if bitboard = 0
 */
U32 findFirstOneInBitBoard(BITBOARD bitboard)
{
	if (bitboard.bb[0])
	{
		return findFirstOne(bitboard.bb[0]);
	}
	else if (bitboard.bb[1])
	{
		return 30 + findFirstOne(bitboard.bb[1]);
	}
	else if (bitboard.bb[2])
	{
		return 60 + findFirstOne(bitboard.bb[2]);
	}
	else
	{
		return 0;
	}
}

/**
 * Don't use this if bitboard = 0
 */
U32 findLastOneInBitBoard(BITBOARD bitboard)
{
	if (bitboard.bb[2])
	{
		return 60 + findLastOne(bitboard.bb[2]);
	}
	else if (bitboard.bb[1])
	{
		return 30 + findLastOne(bitboard.bb[1]);
	}
	else if (bitboard.bb[0])
	{
		return findLastOne(bitboard.bb[0]);
	}
	else
	{
		return 0;
	}
}

unsigned int bitCnt(U32 u32)
{
	// MIT HAKMEM algorithm, see http://graphics.stanford.edu/~seander/bithacks.html

	static const U32  M1 = 0x55555555;  // 1 zero,  1 one ...
	static const U32  M2 = 0x33333333;  // 2 zeros,  2 ones ...
	static const U32  M4 = 0x0F0F0F0F;  // 4 zeros,  4 ones ...
	static const U32  M8 = 0x00FF00FF;  // 8 zeros,  8 ones ...
	static const U32 M16 = 0x0000FFFF;  // 16 zeros, 16 ones ...

	u32 = (u32 & M1 ) + ((u32 >>  1) & M1 );   //put count of each  2 bits into those  2 bits
	u32 = (u32 & M2 ) + ((u32 >>  2) & M2 );   //put count of each  4 bits into those  4 bits
	u32 = (u32 & M4 ) + ((u32 >>  4) & M4 );   //put count of each  8 bits into those  8 bits
	u32 = (u32 & M8 ) + ((u32 >>  8) & M8 );   //put count of each 16 bits into those 16 bits
	u32 = (u32 & M16) + ((u32 >> 16) & M16);   //put count of each 32 bits into those 32 bits

	return (int)u32;
}

unsigned int bitCntBB(BITBOARD bitboard)
{
	return bitCnt(bitboard.bb[0]) + bitCnt(bitboard.bb[1]) + bitCnt(bitboard.bb[2]);
}


void initBoard(BOARD* m_board)
{
	m_board->nextMove = WHITE_MOVE;
	m_board->viewRotated = FALSE;

	int i;
	for (i = 0; i < 90; i++)
	{
		m_board->square[i] = EMPTY;
	}

	// RHEAKAEHR
	m_board->square[A0] = WHITE_ROOK;
	m_board->square[B0] = WHITE_HORSE;
	m_board->square[C0] = WHITE_ELEPHANT;
	m_board->square[D0] = WHITE_ADVISOR;
	m_board->square[E0] = WHITE_KING;
	m_board->square[F0] = WHITE_ADVISOR;
	m_board->square[G0] = WHITE_ELEPHANT;
	m_board->square[H0] = WHITE_HORSE;
	m_board->square[I0] = WHITE_ROOK;

	// rheakaehr
	m_board->square[A9] = BLACK_ROOK;
	m_board->square[B9] = BLACK_HORSE;
	m_board->square[C9] = BLACK_ELEPHANT;
	m_board->square[D9] = BLACK_ADVISOR;
	m_board->square[E9] = BLACK_KING;
	m_board->square[F9] = BLACK_ADVISOR;
	m_board->square[G9] = BLACK_ELEPHANT;
	m_board->square[H9] = BLACK_HORSE;
	m_board->square[I9] = BLACK_ROOK;

	// 1C5C1
	m_board->square[B2] = WHITE_CANNON;
	m_board->square[H2] = WHITE_CANNON;

	// 1c5c1
	m_board->square[B7] = BLACK_CANNON;
	m_board->square[H7] = BLACK_CANNON;

	// P1P1P1P1P
	m_board->square[A3] = WHITE_PAWN;
	m_board->square[C3] = WHITE_PAWN;
	m_board->square[E3] = WHITE_PAWN;
	m_board->square[G3] = WHITE_PAWN;
	m_board->square[I3] = WHITE_PAWN;

	// p1p1p1p1p1
	m_board->square[A6] = BLACK_PAWN;
	m_board->square[C6] = BLACK_PAWN;
	m_board->square[E6] = BLACK_PAWN;
	m_board->square[G6] = BLACK_PAWN;
	m_board->square[I6] = BLACK_PAWN;

	initBoardFromSquares(m_board, m_board->square, WHITE_MOVE);

	return;
}

void displayBoard(BOARD m_board)
{
	int rank, file;
	if (m_board.viewRotated)
	{
		printf("  i h g f e d c b a\n");
		printf("-|-----------------|-\n");
		for (rank = 0; rank < 10; rank++)
		{
			for (file = 8; file >= 0; file--)
			{
				if (file == 8)
					printf(" |%c", PIECENAMES[m_board.square[BOARDINDEX[file][rank]]]);
				else
					printf(" %c", PIECENAMES[m_board.square[BOARDINDEX[file][rank]]]);
			}
			printf("|%d", rank);
			printf("\n");
		}
		printf("-|-----------------|-\n");
	}
	else
	{
		printf("-|-----------------|-\n");
		for (rank = 9; rank >= 0; rank--)
		{
			printf("%d|", rank);
			for (file = 0; file < 9; file++)
			{
				if (file < 8)
					printf("%c ", PIECENAMES[m_board.square[BOARDINDEX[file][rank]]]);
				else
					printf("%c", PIECENAMES[m_board.square[BOARDINDEX[file][rank]]]);
			}
			printf("|\n");
		}
		printf("-|-----------------|-\n");
		printf("  a b c d e f g h i\n");
	}

	return;
}

void initBoardFromSquares(BOARD* m_board, int m_square[90], unsigned char m_nextMove)
{
	// sets up the board variables according to the information found in the square[90] array

	// setting all bits to 0
	clearBitBoard(&m_board->whiteKing);
	clearBitBoard(&m_board->whiteAdvisors);
	clearBitBoard(&m_board->whiteElephants);
	clearBitBoard(&m_board->whiteRooks);
	clearBitBoard(&m_board->whiteCannons);
	clearBitBoard(&m_board->whiteHorses);
	clearBitBoard(&m_board->whitePawns);

	clearBitBoard(&m_board->blackKing);
	clearBitBoard(&m_board->blackAdvisors);
	clearBitBoard(&m_board->blackElephants);
	clearBitBoard(&m_board->blackRooks);
	clearBitBoard(&m_board->blackCannons);
	clearBitBoard(&m_board->blackHorses);
	clearBitBoard(&m_board->blackPawns);

	// populate all bitboards:
	int i;
	for (i = 0; i < 90; i++)
	{
		m_board->square[i] = m_square[i];

		if (m_square[i] == WHITE_KING)
			m_board->whiteKing = orTwoBitBoards(m_board->whiteKing, BITBOARDSET[i]);
		if (m_square[i] == WHITE_ADVISOR)
			m_board->whiteAdvisors = orTwoBitBoards(m_board->whiteAdvisors, BITBOARDSET[i]);
		if (m_square[i] == WHITE_ELEPHANT)
			m_board->whiteElephants = orTwoBitBoards(m_board->whiteElephants, BITBOARDSET[i]);
		if (m_square[i] == WHITE_ROOK)
			m_board->whiteRooks = orTwoBitBoards(m_board->whiteRooks, BITBOARDSET[i]);
		if (m_square[i] == WHITE_CANNON)
			m_board->whiteCannons = orTwoBitBoards(m_board->whiteCannons, BITBOARDSET[i]);
		if (m_square[i] == WHITE_HORSE)
			m_board->whiteHorses = orTwoBitBoards(m_board->whiteHorses, BITBOARDSET[i]);
		if (m_square[i] == WHITE_PAWN)
			m_board->whitePawns = orTwoBitBoards(m_board->whitePawns, BITBOARDSET[i]);

		if (m_square[i] == BLACK_KING)
			m_board->blackKing = orTwoBitBoards(m_board->blackKing, BITBOARDSET[i]);
		if (m_square[i] == BLACK_ADVISOR)
			m_board->blackAdvisors = orTwoBitBoards(m_board->blackAdvisors, BITBOARDSET[i]);
		if (m_square[i] == BLACK_ELEPHANT)
			m_board->blackElephants = orTwoBitBoards(m_board->blackElephants, BITBOARDSET[i]);
		if (m_square[i] == BLACK_ROOK)
			m_board->blackRooks = orTwoBitBoards(m_board->blackRooks, BITBOARDSET[i]);
		if (m_square[i] == BLACK_CANNON)
			m_board->blackCannons = orTwoBitBoards(m_board->blackCannons, BITBOARDSET[i]);
		if (m_square[i] == BLACK_HORSE)
			m_board->blackHorses = orTwoBitBoards(m_board->blackHorses, BITBOARDSET[i]);
		if (m_square[i] == BLACK_PAWN)
			m_board->blackPawns = orTwoBitBoards(m_board->blackPawns, BITBOARDSET[i]);
	}

	BITBOARD whitePieces[] = {m_board->whiteKing, m_board->whiteAdvisors, m_board->whiteElephants,
			m_board->whiteRooks, m_board->whiteCannons, m_board->whiteHorses, m_board->whitePawns
	};
	m_board->whitePieces = orMultipleBitBoards(whitePieces, 7);

	BITBOARD blackPieces[] = {m_board->blackKing, m_board->blackAdvisors, m_board->blackElephants,
			m_board->blackRooks, m_board->blackCannons, m_board->blackHorses, m_board->blackPawns
	};
	m_board->blackPieces = orMultipleBitBoards(blackPieces, 7);

	m_board->occupiedSquares = orTwoBitBoards(m_board->whitePieces, m_board->blackPieces);

	m_board->nextMove = m_nextMove;

	// default search depth for startup
	m_board->searchDepth = DEFAULT_SEARCH_DEPTH;

	// default search time for startup, milliseconds
	m_board->maxTime = DEFAULT_SEARCH_TIME;

	m_board->timer.startTime = 0;
	m_board->timer.stopTime = 0;
	m_board->timer.stopTimeDelta = 0;
	m_board->timer.running = FALSE;


	// Initialize material
	int whitePawns, whiteAdvisors, whiteElephants, whiteRooks, whiteCannons, whiteHorses;
	int blackPawns, blackAdvisors, blackElephants, blackRooks, blackCannons, blackHorses;
	int whiteTotal, blackTotal;

	whitePawns = bitCntBB(board.whitePawns);
	whiteAdvisors = bitCntBB(board.whiteAdvisors);
	whiteElephants = bitCntBB(board.whiteElephants);
	whiteRooks = bitCntBB(board.whiteRooks);
	whiteCannons = bitCntBB(board.whiteCannons);
	whiteHorses = bitCntBB(board.whiteHorses);

	blackPawns = bitCntBB(board.blackPawns);
	blackAdvisors = bitCntBB(board.blackAdvisors);
	blackElephants = bitCntBB(board.blackElephants);
	blackRooks = bitCntBB(board.blackRooks);
	blackCannons = bitCntBB(board.blackCannons);
	blackHorses = bitCntBB(board.blackHorses);

	whiteTotal = whitePawns*PAWN_VALUE + whiteAdvisors*ADVISOR_VALUE
			+ whiteElephants*ELEPHANT_VALUE + whiteRooks*ROOK_VALUE
			+ whiteCannons*CANNON_VALUE + whiteHorses*HORSE_VALUE;

	blackTotal = blackPawns*PAWN_VALUE + blackAdvisors*ADVISOR_VALUE
			+ blackElephants*ELEPHANT_VALUE + blackRooks*ROOK_VALUE
			+ blackCannons*CANNON_VALUE + blackHorses*HORSE_VALUE;

	board.material = whiteTotal - blackTotal;

	board.endOfGame = 0;
	board.endOfSearch = 0;
	for (i = 0; i < MAX_PLY; i++)
	{
		board.moveBufLen[i] = 0;
		board.triangularLength[i] = 0;
	}
	board.inodes = 0;

	return;
}



void readCommands()
{
	int nextc;

	if (board.nextMove == WHITE_MOVE)
	{
		printf("wt> ");
	}
	else
	{
		printf("bl> ");
	}
	fflush(stdout);

	//     ===========================================================================
	//     Read a command and call doCommand:
	//     ===========================================================================

	while ((nextc = getc(stdin)) != EOF)
	{
		if (nextc == '\n')
		{
			CMD_BUFF[CMD_BUFF_COUNT] = '\0';
			while (CMD_BUFF_COUNT)
			{
				if (!doCommand(CMD_BUFF)) return;
			}

			if (board.nextMove == WHITE_MOVE)
			{
				printf("wt> ");
			}
			else
			{
				printf("bl> ");
			}
			fflush(stdout);
		}
		else
		{
			if (CMD_BUFF_COUNT >= MAX_CMD_BUFF-1)
			{
				printf("Warning: command buffer full !! \n");
				CMD_BUFF_COUNT = 0;
			}
			CMD_BUFF[CMD_BUFF_COUNT++] = nextc;
		}
	}

	return;
}

BOOL doCommand(const char *buf)
{
	char userinput[MAX_CMD_BUFF];
	MOVE move;
	TIMER timer;
	U64 msStart;
	U64 msStop;
	U64 perftcount;
	int number;

	//     =================================================================
	//  return when command buffer is empty
	//     =================================================================

	if (!strcmp(buf, ""))
	{
		CMD_BUFF_COUNT = 0;
		return TRUE;
	}

	//     =================================================================
	//  help, h, or ?: show this help
	//     =================================================================
	if ((!strcmp(buf, "help")) || (!strcmp(buf, "h")) || (!strcmp(buf, "?")))
	{
		printf("help:\n");
		printf("black               : BLACK to move\n");
		printf("d                   : display board \n");
		printf("exit                : exit program \n");
		printf("go                  : computer next move \n");
		printf("help, h, or ?       : show this help \n");
		printf("info                : display variables (for testing purposes)\n");
		printf("move b2e2           : enter a move (use this format)\n");
		printf("moves               : show all legal moves\n");
		printf("perft n             : calculate raw number of nodes from here, depth n \n");
		printf("quit                : exit program \n");
		printf("r                   : rotate board \n");
		printf("sd n                : set the search depth to n\n");
		printf("time s              : time per move in seconds\n");
		printf("undo                : take back last move\n");
		printf("white               : WHITE to move\n");
		CMD_BUFF_COUNT = 0;
		return TRUE;
	}

	//     =================================================================
	//  exit or quit: exit program
	//     =================================================================
	if ((!strcmp(buf, "exit")) || (!strcmp(buf, "quit")))
	{
		CMD_BUFF_COUNT = 0;
		return FALSE;
	}

	//     =================================================================
	//  d: display board
	//     =================================================================
	if (!strcmp(buf, "d"))
	{
		displayBoard(board);
		CMD_BUFF_COUNT = 0;
		return TRUE;
	}

	//     =================================================================
	//  black: black to move
	//     =================================================================
	if (!strcmp(buf, "black"))
	{
		board.nextMove = BLACK_MOVE;
		CMD_BUFF_COUNT = 0;
		return TRUE;
	}

	//     =================================================================
	//  white: white to move
	//     =================================================================
	if (!strcmp(buf, "white"))
	{
		board.nextMove = WHITE_MOVE;
		CMD_BUFF_COUNT = 0;
		return TRUE;
	}


	//     =================================================================
	//  r: rotate board
	//     =================================================================
	if (!strcmp(buf, "r"))
	{
		board.viewRotated = !board.viewRotated;
		displayBoard(board);
		CMD_BUFF_COUNT = 0;
		return TRUE;
	}

	//	=================================================================
	//  moves: show all legal moves
	//	=================================================================
	if (!strcmp(buf, "moves"))
	{
		board.moveBufLen[0] = 0;
		int i;

		board.moveBufLen[1] = movegen(board.moveBufLen[0]);

		printf("pseudo-legal moves from this position:\n");
		for (i = board.moveBufLen[0]; i < board.moveBufLen[1]; i++)
		{
			printf("%d. ", i+1);
			displayMove(board.moveBuffer[i]);
			printf("\n");
		}
		CMD_BUFF_COUNT = 0;

		return TRUE;
	}


	//	=================================================================
	//  move (do a move) [console mode only]
	//	=================================================================

	if (!strncmp(buf, "move", 4))
	{
		sscanf(buf + 4, "%s", userinput);

		// generate the pseudo-legal move list
		board.moveBufLen[0] = 0;
		board.moveBufLen[1] = movegen(board.moveBufLen[0]);

		// check to see if the user move is also found in the pseudo-legal move list
		if (isValidTextMove(userinput, &move))
		{
			makeMove(move);

			// post-move check to see if two kings face to face directly
			if (isTwoKingsFaceToFace())
			{
				unMakeMove(move);
				printf("invalid move, two kings face to face directly: %s\n", userinput);
			}
			// post-move check to see if we are leaving our king in check
			else if (isOtherKingAttacked())
			{
				unMakeMove(move);
				printf("invalid move, leaving king in check: %s\n", userinput);
			}
			else
			{
				board.endOfGame++;
				board.endOfSearch = board.endOfGame;
				displayBoard(board);
			}
		}
		else
		{
			printf("move is invalid or not recognized: %s\n", userinput);
		}

		CMD_BUFF_COUNT = 0;
		return TRUE;
	}

	//     =================================================================
	//  undo: take back last move
	//     =================================================================
	if (!strcmp(buf, "undo"))
	{
		if (board.endOfGame)
		{
			unMakeMove(board.gameLine[--board.endOfGame].move);
			board.endOfSearch = board.endOfGame;
			displayBoard(board);
		}
		else
			printf("already at start of game\n");

		CMD_BUFF_COUNT = 0;
		return TRUE;
	}

	//     =================================================================
	//  sd n: set the search depth to n
	//     =================================================================
	if (!strncmp(buf, "sd", 2))
	{
		sscanf(buf + 2, "%d", &board.searchDepth);
		printf("search depth is set to %d\n", board.searchDepth);

		CMD_BUFF_COUNT = 0;
		return TRUE;
	}

	//     =================================================================
	//  go: computer next move
	//     =================================================================
	if (!strcmp(buf, "go"))
	{
		move = think();
		if (move.moveInt)
		{
			makeMove(move);
			board.endOfGame++;
			board.endOfSearch = board.endOfGame;
			displayBoard(board);
		}

		CMD_BUFF_COUNT = 0;
		return TRUE;
	}

	// =================================================================
	// perft n  : calculate raw number of nodes from here, depth n
	// =================================================================

	if (!strncmp(buf, "perft", 5))
	{
		sscanf(buf+5,"%d", &number);
		printf("    starting perft %d...\n", number);

		initTimer(&timer);
		board.moveBufLen[0] = 0;

		msStart = getMSTimer(&timer);
		perftcount = perft(0, number);
		msStop = getMSTimer(&timer);

		printf("nodes        = %"PRINTF_INT64_MODIFIER"u, %"PRINTF_INT64_MODIFIER"u ms, ", perftcount, msStop - msStart);

		if ((msStop - msStart) > 0)
			printf("%"PRINTF_INT64_MODIFIER"u  knods/s", perftcount/(msStop - msStart));
		printf("\n");

		CMD_BUFF_COUNT = 0;

		return TRUE;
	}

	// =================================================================
	// time s : time per move in seconds
	// =================================================================

	if (!strncmp(buf, "time", 4))
	{
		number = (int)board.maxTime / 1000;
		sscanf(buf+4,"%d", &number);
		if (number < 1) number = 1;
		printf("search time is set to %d seconds\n", number);
		board.maxTime = number * 1000; // conversion to ms

		CMD_BUFF_COUNT = 0;

		return TRUE;
	}

	//     =================================================================
	//  unknown command
	//     =================================================================
	printf("    command not implemented: %s, type 'help' for more info\n", buf);
	CMD_BUFF_COUNT = 0;
	return TRUE;
}



void initData()
{
	int i, file, rank, arank, afile;
	//     ===========================================================================
	//     BITSET has only one bit set
	//     ===========================================================================
	BITSET[0] = 0x00000001;
	for (i = 1; i < 30 ; i++)
	{
		BITSET[i] = BITSET[i-1] << 1;
	}

	//     ===========================================================================
	//     BITBOARDSET has only one bit set
	//     ===========================================================================
	for (i = 0; i < 90 ; i++)
	{
		clearBitBoard(&BITBOARDSET[i]);
		BITBOARDSET[i].bb[SQUARE_TO_BITBOARD_INDEX[i]] = BITSET[SQUARE_TO_BITSET_INDEX[i]];
	}

	//     ===========================================================================
	//     BOARDINDEX is used to translate [file][rank] to [square],
	//     Note that file is from 0..8 and rank from 0..9
	//     ===========================================================================
	for (rank = 0 ; rank < 10; rank++)
	{
		for (file = 0 ; file < 9; file++)
		{
			BOARDINDEX[file][rank] = rank*9 + file;
		}
	}

	//     ===========================================================================
	//     Initialize all attack bitmaps, used in the move generator (see movegen.c)
	//     ===========================================================================
	int square;
	for (square = 0; square < 90; square++)
	{
		for (i = 0; i < 4; i++)
		{
			clearBitBoard(&HORSE_ATTACKS[square][i]);
			clearBitBoard(&HORSE_OBSTRUCTS[square][i]);
			clearBitBoard(&ELEPHANT_ATTACKS[square][i]);
			clearBitBoard(&ELEPHANT_OBSTRUCTS[square][i]);
		}
		clearBitBoard(&ADVISOR_ATTACKS[square]);
		clearBitBoard(&KING_ATTACKS[square]);
		clearBitBoard(&WHITE_PAWN_ATTACKS[square]);
		clearBitBoard(&BLACK_PAWN_ATTACKS[square]);
		clearBitBoard(&ATTACKS_RIGHT[square]);
		clearBitBoard(&ATTACKS_TOP[square]);
		clearBitBoard(&ATTACKS_LEFT[square]);
		clearBitBoard(&ATTACKS_BOTTOM[square]);
	}

	// HORSE attacks
	// [from][0] => RIGHT-UP, RIGHT-DOWN
	// [from][1] => LEFT-UP, LEFT-DOWN
	// [from][2] => UP-RIGHT, UP-LEFT
	// [from][3] => DOWN-RIGHT, DOWN-LEFT
	// HORSE obstructs
	// [from][0] => RIGHT
	// [from][1] => LEFT
	// [from][2] => UP
	// [from][3] => DOWN
	for (square = 0; square < 90; square++)
	{
		file = FILES[square];
		rank = RANKS[square];

		// [from][0] => RIGHT-UP, RIGHT-DOWN
		afile = file + 2; arank = rank + 1;
		if ((afile >= 0) & (afile <= 8) & (arank >= 0) & (arank <= 9))
			HORSE_ATTACKS[square][0].bb[SQUARE_TO_BITBOARD_INDEX[BOARDINDEX[afile][arank]]] |= BITSET[SQUARE_TO_BITSET_INDEX[BOARDINDEX[afile][arank]]];
		afile = file + 2; arank = rank - 1;
		if ((afile >= 0) & (afile <= 8) & (arank >= 0) & (arank <= 9))
			HORSE_ATTACKS[square][0].bb[SQUARE_TO_BITBOARD_INDEX[BOARDINDEX[afile][arank]]] |= BITSET[SQUARE_TO_BITSET_INDEX[BOARDINDEX[afile][arank]]];
		// [from][0] => RIGHT
		afile = file + 1; arank = rank;
		if ((afile >= 0) & (afile <= 8) & (arank >= 0) & (arank <= 9))
			HORSE_OBSTRUCTS[square][0].bb[SQUARE_TO_BITBOARD_INDEX[BOARDINDEX[afile][arank]]] |= BITSET[SQUARE_TO_BITSET_INDEX[BOARDINDEX[afile][arank]]];

		// [from][2] => LEFT-UP, LEFT-DOWN
		afile = file - 2; arank = rank + 1;
		if ((afile >= 0) & (afile <= 8) & (arank >= 0) & (arank <= 9))
			HORSE_ATTACKS[square][1].bb[SQUARE_TO_BITBOARD_INDEX[BOARDINDEX[afile][arank]]] |= BITSET[SQUARE_TO_BITSET_INDEX[BOARDINDEX[afile][arank]]];
		afile = file - 2; arank = rank - 1;
		if ((afile >= 0) & (afile <= 8) & (arank >= 0) & (arank <= 9))
			HORSE_ATTACKS[square][1].bb[SQUARE_TO_BITBOARD_INDEX[BOARDINDEX[afile][arank]]] |= BITSET[SQUARE_TO_BITSET_INDEX[BOARDINDEX[afile][arank]]];
		// [from][1] => LEFT
		afile = file - 1; arank = rank;
		if ((afile >= 0) & (afile <= 8) & (arank >= 0) & (arank <= 9))
			HORSE_OBSTRUCTS[square][1].bb[SQUARE_TO_BITBOARD_INDEX[BOARDINDEX[afile][arank]]] |= BITSET[SQUARE_TO_BITSET_INDEX[BOARDINDEX[afile][arank]]];

		// [from][4] => UP-RIGHT, UP-LEFT
		afile = file + 1; arank = rank + 2;
		if ((afile >= 0) & (afile <= 8) & (arank >= 0) & (arank <= 9))
			HORSE_ATTACKS[square][2].bb[SQUARE_TO_BITBOARD_INDEX[BOARDINDEX[afile][arank]]] |= BITSET[SQUARE_TO_BITSET_INDEX[BOARDINDEX[afile][arank]]];
		afile = file - 1; arank = rank + 2;
		if ((afile >= 0) & (afile <= 8) & (arank >= 0) & (arank <= 9))
			HORSE_ATTACKS[square][2].bb[SQUARE_TO_BITBOARD_INDEX[BOARDINDEX[afile][arank]]] |= BITSET[SQUARE_TO_BITSET_INDEX[BOARDINDEX[afile][arank]]];
		// [from][2] => UP
		afile = file; arank = rank + 1;
		if ((afile >= 0) & (afile <= 8) & (arank >= 0) & (arank <= 9))
			HORSE_OBSTRUCTS[square][2].bb[SQUARE_TO_BITBOARD_INDEX[BOARDINDEX[afile][arank]]] |= BITSET[SQUARE_TO_BITSET_INDEX[BOARDINDEX[afile][arank]]];

		// [from][6] => DOWN-RIGHT, DOWN-LEFT
		afile = file + 1; arank = rank - 2;
		if ((afile >= 0) & (afile <= 8) & (arank >= 0) & (arank <= 9))
			HORSE_ATTACKS[square][3].bb[SQUARE_TO_BITBOARD_INDEX[BOARDINDEX[afile][arank]]] |= BITSET[SQUARE_TO_BITSET_INDEX[BOARDINDEX[afile][arank]]];
		afile = file - 1; arank = rank - 2;
		if ((afile >= 0) & (afile <= 8) & (arank >= 0) & (arank <= 9))
			HORSE_ATTACKS[square][3].bb[SQUARE_TO_BITBOARD_INDEX[BOARDINDEX[afile][arank]]] |= BITSET[SQUARE_TO_BITSET_INDEX[BOARDINDEX[afile][arank]]];
		// [from][3] => DOWN
		afile = file; arank = rank - 1;
		if ((afile >= 0) & (afile <= 8) & (arank >= 0) & (arank <= 9))
			HORSE_OBSTRUCTS[square][3].bb[SQUARE_TO_BITBOARD_INDEX[BOARDINDEX[afile][arank]]] |= BITSET[SQUARE_TO_BITSET_INDEX[BOARDINDEX[afile][arank]]];
	}

	// ELEPHANT attacks, obstructs
	// [from][0] => RIGHT-UP
	// [from][1] => RIGHT-DOWN
	// [from][2] => LEFT-UP
	// [from][3] => LEFT-DOWN
	ELEPHANT_ATTACKS[C0][0] = orTwoBitBoards(ELEPHANT_ATTACKS[C0][0], BITBOARDSET[A2]);
	ELEPHANT_ATTACKS[C0][2] = orTwoBitBoards(ELEPHANT_ATTACKS[C0][2], BITBOARDSET[E2]);
	ELEPHANT_OBSTRUCTS[C0][0] = orTwoBitBoards(ELEPHANT_OBSTRUCTS[C0][0], BITBOARDSET[B1]);
	ELEPHANT_OBSTRUCTS[C0][2] = orTwoBitBoards(ELEPHANT_OBSTRUCTS[C0][2], BITBOARDSET[D1]);

	ELEPHANT_ATTACKS[G0][0] = orTwoBitBoards(ELEPHANT_ATTACKS[G0][0], BITBOARDSET[E2]);
	ELEPHANT_ATTACKS[G0][2] = orTwoBitBoards(ELEPHANT_ATTACKS[G0][2], BITBOARDSET[I2]);
	ELEPHANT_OBSTRUCTS[G0][0] = orTwoBitBoards(ELEPHANT_OBSTRUCTS[G0][0], BITBOARDSET[F1]);
	ELEPHANT_OBSTRUCTS[G0][2] = orTwoBitBoards(ELEPHANT_OBSTRUCTS[G0][2], BITBOARDSET[H1]);

	ELEPHANT_ATTACKS[A2][0] = orTwoBitBoards(ELEPHANT_ATTACKS[A2][0], BITBOARDSET[C0]);
	ELEPHANT_ATTACKS[A2][1] = orTwoBitBoards(ELEPHANT_ATTACKS[A2][1], BITBOARDSET[C4]);
	ELEPHANT_OBSTRUCTS[A2][0] = orTwoBitBoards(ELEPHANT_OBSTRUCTS[A2][0], BITBOARDSET[B1]);
	ELEPHANT_OBSTRUCTS[A2][1] = orTwoBitBoards(ELEPHANT_OBSTRUCTS[A2][1], BITBOARDSET[B3]);


	ELEPHANT_ATTACKS[E2][0] = orTwoBitBoards(ELEPHANT_ATTACKS[E2][0], BITBOARDSET[C0]);
	ELEPHANT_ATTACKS[E2][1] = orTwoBitBoards(ELEPHANT_ATTACKS[E2][1], BITBOARDSET[G0]);
	ELEPHANT_ATTACKS[E2][2] = orTwoBitBoards(ELEPHANT_ATTACKS[E2][2], BITBOARDSET[C4]);
	ELEPHANT_ATTACKS[E2][3] = orTwoBitBoards(ELEPHANT_ATTACKS[E2][3], BITBOARDSET[G4]);
	ELEPHANT_OBSTRUCTS[E2][0] = orTwoBitBoards(ELEPHANT_OBSTRUCTS[E2][0], BITBOARDSET[D1]);
	ELEPHANT_OBSTRUCTS[E2][1] = orTwoBitBoards(ELEPHANT_OBSTRUCTS[E2][1], BITBOARDSET[F1]);
	ELEPHANT_OBSTRUCTS[E2][2] = orTwoBitBoards(ELEPHANT_OBSTRUCTS[E2][2], BITBOARDSET[D3]);
	ELEPHANT_OBSTRUCTS[E2][3] = orTwoBitBoards(ELEPHANT_OBSTRUCTS[E2][3], BITBOARDSET[F3]);

	ELEPHANT_ATTACKS[I2][2] = orTwoBitBoards(ELEPHANT_ATTACKS[I2][2], BITBOARDSET[G0]);
	ELEPHANT_ATTACKS[I2][3] = orTwoBitBoards(ELEPHANT_ATTACKS[I2][3], BITBOARDSET[G4]);
	ELEPHANT_OBSTRUCTS[I2][2] = orTwoBitBoards(ELEPHANT_OBSTRUCTS[I2][2], BITBOARDSET[H1]);
	ELEPHANT_OBSTRUCTS[I2][3] = orTwoBitBoards(ELEPHANT_OBSTRUCTS[I2][3], BITBOARDSET[H3]);

	ELEPHANT_ATTACKS[C4][1] = orTwoBitBoards(ELEPHANT_ATTACKS[C4][1], BITBOARDSET[A2]);
	ELEPHANT_ATTACKS[C4][3] = orTwoBitBoards(ELEPHANT_ATTACKS[C4][3], BITBOARDSET[E2]);
	ELEPHANT_OBSTRUCTS[C4][1] = orTwoBitBoards(ELEPHANT_OBSTRUCTS[C4][1], BITBOARDSET[B3]);
	ELEPHANT_OBSTRUCTS[C4][3] = orTwoBitBoards(ELEPHANT_OBSTRUCTS[C4][3], BITBOARDSET[D3]);

	ELEPHANT_ATTACKS[G4][1] = orTwoBitBoards(ELEPHANT_ATTACKS[G4][1], BITBOARDSET[E2]);
	ELEPHANT_ATTACKS[G4][3] = orTwoBitBoards(ELEPHANT_ATTACKS[G4][3], BITBOARDSET[I2]);
	ELEPHANT_OBSTRUCTS[G4][1] = orTwoBitBoards(ELEPHANT_OBSTRUCTS[G4][1], BITBOARDSET[F3]);
	ELEPHANT_OBSTRUCTS[G4][3] = orTwoBitBoards(ELEPHANT_OBSTRUCTS[G4][3], BITBOARDSET[H3]);

	ELEPHANT_ATTACKS[C9][1] = orTwoBitBoards(ELEPHANT_ATTACKS[C9][1], BITBOARDSET[A7]);
	ELEPHANT_ATTACKS[C9][3] = orTwoBitBoards(ELEPHANT_ATTACKS[C9][3], BITBOARDSET[E7]);
	ELEPHANT_OBSTRUCTS[C9][1] = orTwoBitBoards(ELEPHANT_OBSTRUCTS[C9][1], BITBOARDSET[B8]);
	ELEPHANT_OBSTRUCTS[C9][3] = orTwoBitBoards(ELEPHANT_OBSTRUCTS[C9][3], BITBOARDSET[D8]);

	ELEPHANT_ATTACKS[G9][1] = orTwoBitBoards(ELEPHANT_ATTACKS[G9][1], BITBOARDSET[E7]);
	ELEPHANT_ATTACKS[G9][3] = orTwoBitBoards(ELEPHANT_ATTACKS[G9][3], BITBOARDSET[I7]);
	ELEPHANT_OBSTRUCTS[G9][1] = orTwoBitBoards(ELEPHANT_OBSTRUCTS[G9][1], BITBOARDSET[F8]);
	ELEPHANT_OBSTRUCTS[G9][3] = orTwoBitBoards(ELEPHANT_OBSTRUCTS[G9][3], BITBOARDSET[H8]);

	ELEPHANT_ATTACKS[A7][0] = orTwoBitBoards(ELEPHANT_ATTACKS[A7][0], BITBOARDSET[C9]);
	ELEPHANT_ATTACKS[A7][1] = orTwoBitBoards(ELEPHANT_ATTACKS[A7][1], BITBOARDSET[C5]);
	ELEPHANT_OBSTRUCTS[A7][0] = orTwoBitBoards(ELEPHANT_OBSTRUCTS[A7][0], BITBOARDSET[B8]);
	ELEPHANT_OBSTRUCTS[A7][1] = orTwoBitBoards(ELEPHANT_OBSTRUCTS[A7][1], BITBOARDSET[B6]);

	ELEPHANT_ATTACKS[E7][0] = orTwoBitBoards(ELEPHANT_ATTACKS[E7][0], BITBOARDSET[C9]);
	ELEPHANT_ATTACKS[E7][1] = orTwoBitBoards(ELEPHANT_ATTACKS[E7][1], BITBOARDSET[G9]);
	ELEPHANT_ATTACKS[E7][2] = orTwoBitBoards(ELEPHANT_ATTACKS[E7][2], BITBOARDSET[C5]);
	ELEPHANT_ATTACKS[E7][3] = orTwoBitBoards(ELEPHANT_ATTACKS[E7][3], BITBOARDSET[G5]);
	ELEPHANT_OBSTRUCTS[E7][0] = orTwoBitBoards(ELEPHANT_OBSTRUCTS[E7][0], BITBOARDSET[D8]);
	ELEPHANT_OBSTRUCTS[E7][1] = orTwoBitBoards(ELEPHANT_OBSTRUCTS[E7][1], BITBOARDSET[F8]);
	ELEPHANT_OBSTRUCTS[E7][2] = orTwoBitBoards(ELEPHANT_OBSTRUCTS[E7][2], BITBOARDSET[D6]);
	ELEPHANT_OBSTRUCTS[E7][3] = orTwoBitBoards(ELEPHANT_OBSTRUCTS[E7][3], BITBOARDSET[F6]);

	ELEPHANT_ATTACKS[I7][2] = orTwoBitBoards(ELEPHANT_ATTACKS[I7][2], BITBOARDSET[G9]);
	ELEPHANT_ATTACKS[I7][3] = orTwoBitBoards(ELEPHANT_ATTACKS[I7][3], BITBOARDSET[G5]);
	ELEPHANT_OBSTRUCTS[I7][2] = orTwoBitBoards(ELEPHANT_OBSTRUCTS[I7][2], BITBOARDSET[H8]);
	ELEPHANT_OBSTRUCTS[I7][3] = orTwoBitBoards(ELEPHANT_OBSTRUCTS[I7][3], BITBOARDSET[H6]);

	ELEPHANT_ATTACKS[C5][0] = orTwoBitBoards(ELEPHANT_ATTACKS[C5][0], BITBOARDSET[A7]);
	ELEPHANT_ATTACKS[C5][2] = orTwoBitBoards(ELEPHANT_ATTACKS[C5][2], BITBOARDSET[E7]);
	ELEPHANT_OBSTRUCTS[C5][0] = orTwoBitBoards(ELEPHANT_OBSTRUCTS[C5][0], BITBOARDSET[B6]);
	ELEPHANT_OBSTRUCTS[C5][2] = orTwoBitBoards(ELEPHANT_OBSTRUCTS[C5][2], BITBOARDSET[D6]);

	ELEPHANT_ATTACKS[G5][0] = orTwoBitBoards(ELEPHANT_ATTACKS[G5][0], BITBOARDSET[E7]);
	ELEPHANT_ATTACKS[G5][2] = orTwoBitBoards(ELEPHANT_ATTACKS[G5][2], BITBOARDSET[I7]);
	ELEPHANT_OBSTRUCTS[G5][0] = orTwoBitBoards(ELEPHANT_OBSTRUCTS[G5][0], BITBOARDSET[F6]);
	ELEPHANT_OBSTRUCTS[G5][2] = orTwoBitBoards(ELEPHANT_OBSTRUCTS[G5][2], BITBOARDSET[H6]);

	// ADVISOR attacks
	ADVISOR_ATTACKS[D0] = orTwoBitBoards(ADVISOR_ATTACKS[D0], BITBOARDSET[E1]);
	ADVISOR_ATTACKS[F0] = orTwoBitBoards(ADVISOR_ATTACKS[F0], BITBOARDSET[E1]);
	ADVISOR_ATTACKS[D2] = orTwoBitBoards(ADVISOR_ATTACKS[D2], BITBOARDSET[E1]);
	ADVISOR_ATTACKS[F2] = orTwoBitBoards(ADVISOR_ATTACKS[F2], BITBOARDSET[E1]);
	BITBOARD whiteAdvisorMoves[] = {BITBOARDSET[D0], BITBOARDSET[D2], BITBOARDSET[F0], BITBOARDSET[F2]};
	ADVISOR_ATTACKS[E1] = orMultipleBitBoards(whiteAdvisorMoves, 4);

	ADVISOR_ATTACKS[D9] = orTwoBitBoards(ADVISOR_ATTACKS[D9], BITBOARDSET[E8]);
	ADVISOR_ATTACKS[F9] = orTwoBitBoards(ADVISOR_ATTACKS[F9], BITBOARDSET[E8]);
	ADVISOR_ATTACKS[D2] = orTwoBitBoards(ADVISOR_ATTACKS[D2], BITBOARDSET[E8]);
	ADVISOR_ATTACKS[F2] = orTwoBitBoards(ADVISOR_ATTACKS[F2], BITBOARDSET[E8]);
	BITBOARD blackAdvisorMoves[] = {BITBOARDSET[D9], BITBOARDSET[D7], BITBOARDSET[F9], BITBOARDSET[F7]};
	ADVISOR_ATTACKS[E8] = orMultipleBitBoards(blackAdvisorMoves, 4);

	// KING attacks
	KING_ATTACKS[D0] = orTwoBitBoards(BITBOARDSET[E0], BITBOARDSET[D1]);
	BITBOARD whiteKingMovesAtE0[] = {BITBOARDSET[D0], BITBOARDSET[F0], BITBOARDSET[E1]};
	KING_ATTACKS[E0] = orMultipleBitBoards(whiteKingMovesAtE0, 3);
	KING_ATTACKS[F0] = orTwoBitBoards(BITBOARDSET[E0], BITBOARDSET[F1]);

	BITBOARD whiteKingMovesAtD1[] = {BITBOARDSET[D0], BITBOARDSET[D2], BITBOARDSET[E1]};
	KING_ATTACKS[D1] = orMultipleBitBoards(whiteKingMovesAtD1, 3);
	BITBOARD whiteKingMovesAtE1[] = {BITBOARDSET[D1], BITBOARDSET[F1], BITBOARDSET[E0], BITBOARDSET[E2]};
	KING_ATTACKS[E1] = orMultipleBitBoards(whiteKingMovesAtE1, 4);
	BITBOARD whiteKingMovesAtF1[] = {BITBOARDSET[F0], BITBOARDSET[F2], BITBOARDSET[E1]};
	KING_ATTACKS[F1] = orMultipleBitBoards(whiteKingMovesAtF1, 3);

	KING_ATTACKS[D2] = orTwoBitBoards(BITBOARDSET[E2], BITBOARDSET[D1]);
	BITBOARD whiteKingMovesAtE2[] = {BITBOARDSET[D2], BITBOARDSET[F2], BITBOARDSET[E1]};
	KING_ATTACKS[E2] = orMultipleBitBoards(whiteKingMovesAtE2, 3);
	KING_ATTACKS[F2] = orTwoBitBoards(BITBOARDSET[E2], BITBOARDSET[F1]);

	//.................................................................................//

	KING_ATTACKS[D9] = orTwoBitBoards(BITBOARDSET[E9], BITBOARDSET[D8]);
	BITBOARD blackKingMovesAtE9[] = {BITBOARDSET[D9], BITBOARDSET[F9], BITBOARDSET[E8]};
	KING_ATTACKS[E9] = orMultipleBitBoards(blackKingMovesAtE9, 3);
	KING_ATTACKS[F9] = orTwoBitBoards(BITBOARDSET[E9], BITBOARDSET[F8]);

	BITBOARD blackKingMovesAtD8[] = {BITBOARDSET[D9], BITBOARDSET[D7], BITBOARDSET[E8]};
	KING_ATTACKS[D8] = orMultipleBitBoards(blackKingMovesAtD8, 3);
	BITBOARD blackKingMovesAtE8[] = {BITBOARDSET[D8], BITBOARDSET[F8], BITBOARDSET[E9], BITBOARDSET[E7]};
	KING_ATTACKS[E8] = orMultipleBitBoards(blackKingMovesAtE8, 4);
	BITBOARD blackKingMovesAtF8[] = {BITBOARDSET[F9], BITBOARDSET[F7], BITBOARDSET[E8]};
	KING_ATTACKS[F8] = orMultipleBitBoards(blackKingMovesAtF8, 3);

	KING_ATTACKS[D7] = orTwoBitBoards(BITBOARDSET[E7], BITBOARDSET[D8]);
	BITBOARD blackKingMovesAtE7[] = {BITBOARDSET[D7], BITBOARDSET[F7], BITBOARDSET[E8]};
	KING_ATTACKS[E7] = orMultipleBitBoards(blackKingMovesAtE7, 3);
	KING_ATTACKS[F7] = orTwoBitBoards(BITBOARDSET[E7], BITBOARDSET[F8]);

	// White PAWN attacks
	WHITE_PAWN_ATTACKS[A3] = orTwoBitBoards(WHITE_PAWN_ATTACKS[A3], BITBOARDSET[A4]);
	WHITE_PAWN_ATTACKS[C3] = orTwoBitBoards(WHITE_PAWN_ATTACKS[C3], BITBOARDSET[C4]);
	WHITE_PAWN_ATTACKS[E3] = orTwoBitBoards(WHITE_PAWN_ATTACKS[E3], BITBOARDSET[E4]);
	WHITE_PAWN_ATTACKS[G3] = orTwoBitBoards(WHITE_PAWN_ATTACKS[G3], BITBOARDSET[G4]);
	WHITE_PAWN_ATTACKS[I3] = orTwoBitBoards(WHITE_PAWN_ATTACKS[I3], BITBOARDSET[I4]);

	WHITE_PAWN_ATTACKS[A4] = orTwoBitBoards(WHITE_PAWN_ATTACKS[A4], BITBOARDSET[A5]);
	WHITE_PAWN_ATTACKS[C4] = orTwoBitBoards(WHITE_PAWN_ATTACKS[C4], BITBOARDSET[C5]);
	WHITE_PAWN_ATTACKS[E4] = orTwoBitBoards(WHITE_PAWN_ATTACKS[E4], BITBOARDSET[E5]);
	WHITE_PAWN_ATTACKS[G4] = orTwoBitBoards(WHITE_PAWN_ATTACKS[G4], BITBOARDSET[G5]);
	WHITE_PAWN_ATTACKS[I4] = orTwoBitBoards(WHITE_PAWN_ATTACKS[I4], BITBOARDSET[I5]);

	for (square = A5; square <= I9; square++)
	{
		file = FILES[square];
		rank = RANKS[square];
		afile = file - 1; arank = rank;
		if ((afile >= 0) & (afile <= 8) & (arank >= 0) & (arank <= 9))
			WHITE_PAWN_ATTACKS[square].bb[SQUARE_TO_BITBOARD_INDEX[BOARDINDEX[afile][arank]]] |= BITSET[SQUARE_TO_BITSET_INDEX[BOARDINDEX[afile][arank]]];
		afile = file + 1; arank = rank;
		if ((afile >= 0) & (afile <= 8) & (arank >= 0) & (arank <= 9))
			WHITE_PAWN_ATTACKS[square].bb[SQUARE_TO_BITBOARD_INDEX[BOARDINDEX[afile][arank]]] |= BITSET[SQUARE_TO_BITSET_INDEX[BOARDINDEX[afile][arank]]];
		afile = file; arank = rank + 1;
		if ((afile >= 0) & (afile <= 8) & (arank >= 0) & (arank <= 9))
			WHITE_PAWN_ATTACKS[square].bb[SQUARE_TO_BITBOARD_INDEX[BOARDINDEX[afile][arank]]] |= BITSET[SQUARE_TO_BITSET_INDEX[BOARDINDEX[afile][arank]]];
	}

	BLACK_PAWN_ATTACKS[A6] = orTwoBitBoards(BLACK_PAWN_ATTACKS[A6], BITBOARDSET[A5]);
	BLACK_PAWN_ATTACKS[C6] = orTwoBitBoards(BLACK_PAWN_ATTACKS[C6], BITBOARDSET[C5]);
	BLACK_PAWN_ATTACKS[E6] = orTwoBitBoards(BLACK_PAWN_ATTACKS[E6], BITBOARDSET[E5]);
	BLACK_PAWN_ATTACKS[G6] = orTwoBitBoards(BLACK_PAWN_ATTACKS[G6], BITBOARDSET[G5]);
	BLACK_PAWN_ATTACKS[I6] = orTwoBitBoards(BLACK_PAWN_ATTACKS[I6], BITBOARDSET[I5]);

	BLACK_PAWN_ATTACKS[A5] = orTwoBitBoards(BLACK_PAWN_ATTACKS[A5], BITBOARDSET[A4]);
	BLACK_PAWN_ATTACKS[C5] = orTwoBitBoards(BLACK_PAWN_ATTACKS[C5], BITBOARDSET[C4]);
	BLACK_PAWN_ATTACKS[E5] = orTwoBitBoards(BLACK_PAWN_ATTACKS[E5], BITBOARDSET[E4]);
	BLACK_PAWN_ATTACKS[G5] = orTwoBitBoards(BLACK_PAWN_ATTACKS[G5], BITBOARDSET[G4]);
	BLACK_PAWN_ATTACKS[I5] = orTwoBitBoards(BLACK_PAWN_ATTACKS[I5], BITBOARDSET[I4]);

	for (square = A0; square <= I4; square++)
	{
		file = FILES[square];
		rank = RANKS[square];
		afile = file - 1; arank = rank;
		if ((afile >= 0) & (afile <= 8) & (arank >= 0) & (arank <= 9))
			BLACK_PAWN_ATTACKS[square].bb[SQUARE_TO_BITBOARD_INDEX[BOARDINDEX[afile][arank]]] |= BITSET[SQUARE_TO_BITSET_INDEX[BOARDINDEX[afile][arank]]];
		afile = file + 1; arank = rank;
		if ((afile >= 0) & (afile <= 8) & (arank >= 0) & (arank <= 9))
			BLACK_PAWN_ATTACKS[square].bb[SQUARE_TO_BITBOARD_INDEX[BOARDINDEX[afile][arank]]] |= BITSET[SQUARE_TO_BITSET_INDEX[BOARDINDEX[afile][arank]]];
		afile = file; arank = rank - 1;
		if ((afile >= 0) & (afile <= 8) & (arank >= 0) & (arank <= 9))
			BLACK_PAWN_ATTACKS[square].bb[SQUARE_TO_BITBOARD_INDEX[BOARDINDEX[afile][arank]]] |= BITSET[SQUARE_TO_BITSET_INDEX[BOARDINDEX[afile][arank]]];
	}

	//     ===========================================================================
	//     Initialize ROOK_ATTACKS_RIGHT
	//     ===========================================================================
	for (square = 0; square < 90; square++)
	{
		file = FILES[square];
		rank = RANKS[square];
		afile = file + 1;
		if (afile < 9)
			ATTACKS_RIGHT[square] = orTwoBitBoards(ATTACKS_RIGHT[square], BITBOARDSET[BOARDINDEX[afile][rank]]);
		afile = file + 2;
		if (afile < 9)
			ATTACKS_RIGHT[square] = orTwoBitBoards(ATTACKS_RIGHT[square], BITBOARDSET[BOARDINDEX[afile][rank]]);
		afile = file + 3;
		if (afile < 9)
			ATTACKS_RIGHT[square] = orTwoBitBoards(ATTACKS_RIGHT[square], BITBOARDSET[BOARDINDEX[afile][rank]]);
		afile = file + 4;
		if (afile < 9)
			ATTACKS_RIGHT[square] = orTwoBitBoards(ATTACKS_RIGHT[square], BITBOARDSET[BOARDINDEX[afile][rank]]);
		afile = file + 5;
		if (afile < 9)
			ATTACKS_RIGHT[square] = orTwoBitBoards(ATTACKS_RIGHT[square], BITBOARDSET[BOARDINDEX[afile][rank]]);
		afile = file + 6;
		if (afile < 9)
			ATTACKS_RIGHT[square] = orTwoBitBoards(ATTACKS_RIGHT[square], BITBOARDSET[BOARDINDEX[afile][rank]]);
		afile = file + 7;
		if (afile < 9)
			ATTACKS_RIGHT[square] = orTwoBitBoards(ATTACKS_RIGHT[square], BITBOARDSET[BOARDINDEX[afile][rank]]);
		afile = file + 8;
		if (afile < 9)
			ATTACKS_RIGHT[square] = orTwoBitBoards(ATTACKS_RIGHT[square], BITBOARDSET[BOARDINDEX[afile][rank]]);
	}

	//     ===========================================================================
	//     Initialize ROOK_ATTACKS_TOP
	//     ===========================================================================
	for (square = 0; square < 90; square++)
	{
		file = FILES[square];
		rank = RANKS[square];
		arank = rank + 1;
		if (arank < 10)
			ATTACKS_TOP[square] = orTwoBitBoards(ATTACKS_TOP[square], BITBOARDSET[BOARDINDEX[file][arank]]);
		arank = rank + 2;
		if (arank < 10)
			ATTACKS_TOP[square] = orTwoBitBoards(ATTACKS_TOP[square], BITBOARDSET[BOARDINDEX[file][arank]]);
		arank = rank + 3;
		if (arank < 10)
			ATTACKS_TOP[square] = orTwoBitBoards(ATTACKS_TOP[square], BITBOARDSET[BOARDINDEX[file][arank]]);
		arank = rank + 4;
		if (arank < 10)
			ATTACKS_TOP[square] = orTwoBitBoards(ATTACKS_TOP[square], BITBOARDSET[BOARDINDEX[file][arank]]);
		arank = rank + 5;
		if (arank < 10)
			ATTACKS_TOP[square] = orTwoBitBoards(ATTACKS_TOP[square], BITBOARDSET[BOARDINDEX[file][arank]]);
		arank = rank + 6;
		if (arank < 10)
			ATTACKS_TOP[square] = orTwoBitBoards(ATTACKS_TOP[square], BITBOARDSET[BOARDINDEX[file][arank]]);
		arank = rank + 7;
		if (arank < 10)
			ATTACKS_TOP[square] = orTwoBitBoards(ATTACKS_TOP[square], BITBOARDSET[BOARDINDEX[file][arank]]);
		arank = rank + 8;
		if (arank < 10)
			ATTACKS_TOP[square] = orTwoBitBoards(ATTACKS_TOP[square], BITBOARDSET[BOARDINDEX[file][arank]]);
		arank = rank + 9;
		if (arank < 10)
			ATTACKS_TOP[square] = orTwoBitBoards(ATTACKS_TOP[square], BITBOARDSET[BOARDINDEX[file][arank]]);
	}

	//     ===========================================================================
	//     Initialize ROOK_ATTACKS_LEFT
	//     ===========================================================================
	for (square = 0; square < 90; square++)
	{
		file = FILES[square];
		rank = RANKS[square];
		afile = file - 1;
		if (afile >= 0)
			ATTACKS_LEFT[square] = orTwoBitBoards(ATTACKS_LEFT[square], BITBOARDSET[BOARDINDEX[afile][rank]]);
		afile = file - 2;
		if (afile >= 0)
			ATTACKS_LEFT[square] = orTwoBitBoards(ATTACKS_LEFT[square], BITBOARDSET[BOARDINDEX[afile][rank]]);
		afile = file - 3;
		if (afile >= 0)
			ATTACKS_LEFT[square] = orTwoBitBoards(ATTACKS_LEFT[square], BITBOARDSET[BOARDINDEX[afile][rank]]);
		afile = file - 4;
		if (afile >= 0)
			ATTACKS_LEFT[square] = orTwoBitBoards(ATTACKS_LEFT[square], BITBOARDSET[BOARDINDEX[afile][rank]]);
		afile = file - 5;
		if (afile >= 0)
			ATTACKS_LEFT[square] = orTwoBitBoards(ATTACKS_LEFT[square], BITBOARDSET[BOARDINDEX[afile][rank]]);
		afile = file - 6;
		if (afile >= 0)
			ATTACKS_LEFT[square] = orTwoBitBoards(ATTACKS_LEFT[square], BITBOARDSET[BOARDINDEX[afile][rank]]);
		afile = file - 7;
		if (afile >= 0)
			ATTACKS_LEFT[square] = orTwoBitBoards(ATTACKS_LEFT[square], BITBOARDSET[BOARDINDEX[afile][rank]]);
		afile = file - 8;
		if (afile >= 0)
			ATTACKS_LEFT[square] = orTwoBitBoards(ATTACKS_LEFT[square], BITBOARDSET[BOARDINDEX[afile][rank]]);
	}

	//     ===========================================================================
	//     Initialize ROOK_ATTACKS_BOTTOM
	//     ===========================================================================
	for (square = 0; square < 90; square++)
	{
		file = FILES[square];
		rank = RANKS[square];
		arank = rank - 1;
		if (arank >= 0)
			ATTACKS_BOTTOM[square] = orTwoBitBoards(ATTACKS_BOTTOM[square], BITBOARDSET[BOARDINDEX[file][arank]]);
		arank = rank - 2;
		if (arank >= 0)
			ATTACKS_BOTTOM[square] = orTwoBitBoards(ATTACKS_BOTTOM[square], BITBOARDSET[BOARDINDEX[file][arank]]);
		arank = rank - 3;
		if (arank >= 0)
			ATTACKS_BOTTOM[square] = orTwoBitBoards(ATTACKS_BOTTOM[square], BITBOARDSET[BOARDINDEX[file][arank]]);
		arank = rank - 4;
		if (arank >= 0)
			ATTACKS_BOTTOM[square] = orTwoBitBoards(ATTACKS_BOTTOM[square], BITBOARDSET[BOARDINDEX[file][arank]]);
		arank = rank - 5;
		if (arank >= 0)
			ATTACKS_BOTTOM[square] = orTwoBitBoards(ATTACKS_BOTTOM[square], BITBOARDSET[BOARDINDEX[file][arank]]);
		arank = rank - 6;
		if (arank >= 0)
			ATTACKS_BOTTOM[square] = orTwoBitBoards(ATTACKS_BOTTOM[square], BITBOARDSET[BOARDINDEX[file][arank]]);
		arank = rank - 7;
		if (arank >= 0)
			ATTACKS_BOTTOM[square] = orTwoBitBoards(ATTACKS_BOTTOM[square], BITBOARDSET[BOARDINDEX[file][arank]]);
		arank = rank - 8;
		if (arank >= 0)
			ATTACKS_BOTTOM[square] = orTwoBitBoards(ATTACKS_BOTTOM[square], BITBOARDSET[BOARDINDEX[file][arank]]);
		arank = rank - 9;
		if (arank >= 0)
			ATTACKS_BOTTOM[square] = orTwoBitBoards(ATTACKS_BOTTOM[square], BITBOARDSET[BOARDINDEX[file][arank]]);
	}

	//     ===========================================================================
	//     Initialize the board
	//     ===========================================================================
	initBoard(&board);

	clear(&NOMOVE);

	TOCONSOLE = 1;


	// Winboard parameters:
	XB_NONE = 2;  // not 0 or 1
	XB_ANALYZE = 3;   // not 0, 1, or 2
	XB_MODE = FALSE;
	XB_POST = TRUE;
	XB_PONDER = FALSE;
	XB_DO_PENDING = FALSE;
	XB_NO_TIME_LIMIT = FALSE;

	return;
}


int eval()
{
	int score;
	score = board.material;

	if (board.nextMove)
		return -score;
	else
		return score;
}


// makeMove function used for "move <moveText>" command
void makeMove(MOVE move)
{
	unsigned int from = getFrom(move);
	unsigned int to = getTosq(move);
	unsigned int piece = getPiec(move);
	unsigned int captured = getCapt(move);

	BITBOARD fromBitBoard  = BITBOARDSET[from];
	BITBOARD fromToBitBoard = orTwoBitBoards(fromBitBoard, BITBOARDSET[to]);

	board.gameLine[board.endOfSearch].move.moveInt = move.moveInt;
	board.endOfSearch++;

	board.square[from] = EMPTY;

	switch (piece)
	{
	case 1: // white pawn
		board.square[to] = WHITE_PAWN;
		board.whitePawns = xorTwoBitBoards(board.whitePawns, fromToBitBoard);
		board.whitePieces = xorTwoBitBoards(board.whitePieces, fromToBitBoard);
		break;

	case 2: // white king
		board.square[to] = WHITE_KING;
		board.whiteKing = xorTwoBitBoards(board.whiteKing, fromToBitBoard);
		board.whitePieces = xorTwoBitBoards(board.whitePieces, fromToBitBoard);
		break;

	case 3: // white advisor
		board.square[to] = WHITE_ADVISOR;
		board.whiteAdvisors = xorTwoBitBoards(board.whiteAdvisors, fromToBitBoard);
		board.whitePieces = xorTwoBitBoards(board.whitePieces, fromToBitBoard);
		break;

	case 4: // white elephant
		board.square[to] = WHITE_ELEPHANT;
		board.whiteElephants = xorTwoBitBoards(board.whiteElephants, fromToBitBoard);
		board.whitePieces = xorTwoBitBoards(board.whitePieces, fromToBitBoard);
		break;

	case 5: // white rook
		board.square[to] = WHITE_ROOK;
		board.whiteRooks = xorTwoBitBoards(board.whiteRooks, fromToBitBoard);
		board.whitePieces = xorTwoBitBoards(board.whitePieces, fromToBitBoard);
		break;

	case 6: // white cannon
		board.square[to] = WHITE_CANNON;
		board.whiteCannons = xorTwoBitBoards(board.whiteCannons, fromToBitBoard);
		board.whitePieces = xorTwoBitBoards(board.whitePieces, fromToBitBoard);
		break;

	case 7: // white horse
		board.square[to] = WHITE_HORSE;
		board.whiteHorses = xorTwoBitBoards(board.whiteHorses, fromToBitBoard);
		board.whitePieces = xorTwoBitBoards(board.whitePieces, fromToBitBoard);
		break;

	case 8: // black pawn
		board.square[to] = BLACK_PAWN;
		board.blackPawns = xorTwoBitBoards(board.blackPawns, fromToBitBoard);
		board.blackPieces = xorTwoBitBoards(board.blackPieces, fromToBitBoard);
		break;

	case 9: // black king
		board.square[to] = BLACK_KING;
		board.blackKing = xorTwoBitBoards(board.blackKing, fromToBitBoard);
		board.blackPieces = xorTwoBitBoards(board.blackPieces, fromToBitBoard);
		break;

	case 10: // black advisor
		board.square[to] = BLACK_ADVISOR;
		board.blackAdvisors = xorTwoBitBoards(board.blackAdvisors, fromToBitBoard);
		board.blackPieces = xorTwoBitBoards(board.blackPieces, fromToBitBoard);
		break;

	case 11: // black elephant
		board.square[to] = BLACK_ELEPHANT;
		board.blackElephants = xorTwoBitBoards(board.blackElephants, fromToBitBoard);
		board.blackPieces = xorTwoBitBoards(board.blackPieces, fromToBitBoard);
		break;

	case 12: // black rook
		board.square[to] = BLACK_ROOK;
		board.blackRooks = xorTwoBitBoards(board.blackRooks, fromToBitBoard);
		board.blackPieces = xorTwoBitBoards(board.blackPieces, fromToBitBoard);
		break;

	case 13: // black cannon
		board.square[to] = BLACK_CANNON;
		board.blackCannons = xorTwoBitBoards(board.blackCannons, fromToBitBoard);
		board.blackPieces = xorTwoBitBoards(board.blackPieces, fromToBitBoard);
		break;

	case 14: // black horse
		board.square[to] = BLACK_HORSE;
		board.blackHorses = xorTwoBitBoards(board.blackHorses, fromToBitBoard);
		board.blackPieces = xorTwoBitBoards(board.blackPieces, fromToBitBoard);
		break;
	}

	if (captured)
	{
		makeCapture(captured, to);
		board.occupiedSquares = xorTwoBitBoards(board.occupiedSquares, fromBitBoard);
	}
	else
		board.occupiedSquares = xorTwoBitBoards(board.occupiedSquares, fromToBitBoard);

	board.nextMove = !board.nextMove;
}

// unMakeMove function used for "undo" command
void unMakeMove(MOVE move)
{
	unsigned int piece = getPiec(move);
	unsigned int captured = getCapt(move);
	unsigned int from = getFrom(move);
	unsigned int to = getTosq(move);

	BITBOARD fromBitBoard  = BITBOARDSET[from];
	BITBOARD fromToBitBoard = orTwoBitBoards(fromBitBoard, BITBOARDSET[to]);

	board.square[to] = EMPTY;

	switch (piece)
	{
	case 1: // white pawn:
		board.whitePawns = xorTwoBitBoards(board.whitePawns, fromToBitBoard);
		board.whitePieces = xorTwoBitBoards(board.whitePieces, fromToBitBoard);
		board.square[from] = WHITE_PAWN;
		break;

	case 2: // white king:
		board.whiteKing = xorTwoBitBoards(board.whiteKing, fromToBitBoard);
		board.whitePieces = xorTwoBitBoards(board.whitePieces, fromToBitBoard);
		board.square[from] = WHITE_KING;
		break;

	case 3: // white advisor:
		board.whiteAdvisors = xorTwoBitBoards(board.whiteAdvisors, fromToBitBoard);
		board.whitePieces = xorTwoBitBoards(board.whitePieces, fromToBitBoard);
		board.square[from] = WHITE_ADVISOR;
		break;

	case 4: // white elephant:
		board.whiteElephants = xorTwoBitBoards(board.whiteElephants, fromToBitBoard);
		board.whitePieces = xorTwoBitBoards(board.whitePieces, fromToBitBoard);
		board.square[from] = WHITE_ELEPHANT;
		break;

	case 5: // white rook:
		board.whiteRooks = xorTwoBitBoards(board.whiteRooks, fromToBitBoard);
		board.whitePieces = xorTwoBitBoards(board.whitePieces, fromToBitBoard);
		board.square[from] = WHITE_ROOK;
		break;

	case 6: // white cannon:
		board.whiteCannons = xorTwoBitBoards(board.whiteCannons, fromToBitBoard);
		board.whitePieces = xorTwoBitBoards(board.whitePieces, fromToBitBoard);
		board.square[from] = WHITE_CANNON;
		break;

	case 7: // white horse:
		board.whiteHorses = xorTwoBitBoards(board.whiteHorses, fromToBitBoard);
		board.whitePieces = xorTwoBitBoards(board.whitePieces, fromToBitBoard);
		board.square[from] = WHITE_HORSE;
		break;

	case 8: // black pawn:
		board.blackPawns = xorTwoBitBoards(board.blackPawns, fromToBitBoard);
		board.blackPieces = xorTwoBitBoards(board.blackPieces, fromToBitBoard);
		board.square[from] = BLACK_PAWN;
		break;

	case 9: // black king:
		board.blackKing = xorTwoBitBoards(board.blackKing, fromToBitBoard);
		board.blackPieces = xorTwoBitBoards(board.blackPieces, fromToBitBoard);
		board.square[from] = BLACK_KING;
		break;

	case 10: // black advisor:
		board.blackAdvisors = xorTwoBitBoards(board.blackAdvisors, fromToBitBoard);
		board.blackPieces = xorTwoBitBoards(board.blackPieces, fromToBitBoard);
		board.square[from] = BLACK_ADVISOR;
		break;

	case 11: // black elephant:
		board.blackElephants = xorTwoBitBoards(board.blackElephants, fromToBitBoard);
		board.blackPieces = xorTwoBitBoards(board.blackPieces, fromToBitBoard);
		board.square[from] = BLACK_ELEPHANT;
		break;

	case 12: // black rook:
		board.blackRooks = xorTwoBitBoards(board.blackRooks, fromToBitBoard);
		board.blackPieces = xorTwoBitBoards(board.blackPieces, fromToBitBoard);
		board.square[from] = BLACK_ROOK;
		break;

	case 13: // black cannon:
		board.blackCannons = xorTwoBitBoards(board.blackCannons, fromToBitBoard);
		board.blackPieces = xorTwoBitBoards(board.blackPieces, fromToBitBoard);
		board.square[from] = BLACK_CANNON;
		break;

	case 14: // black horse:
		board.blackHorses = xorTwoBitBoards(board.blackHorses, fromToBitBoard);
		board.blackPieces = xorTwoBitBoards(board.blackPieces, fromToBitBoard);
		board.square[from] = BLACK_HORSE;
		break;
	}

	if (captured)
	{
		unMakeCapture(captured, to);
		board.occupiedSquares = xorTwoBitBoards(board.occupiedSquares, fromBitBoard);
	}
	else
		board.occupiedSquares = xorTwoBitBoards(board.occupiedSquares, fromToBitBoard);

	board.endOfSearch--;

	board.nextMove = !board.nextMove;
}

void makeCapture(unsigned int captured, unsigned int to)
{
	// deals with all captures
	BITBOARD toBitBoard = BITBOARDSET[to];

	switch (captured)
	{
	case 1: // white pawn
		board.whitePawns = xorTwoBitBoards(board.whitePawns, toBitBoard);
		board.whitePieces = xorTwoBitBoards(board.whitePieces, toBitBoard);
		board.material -= PAWN_VALUE;
		break;

	case 2: // white king
		board.whiteKing = xorTwoBitBoards(board.whiteKing, toBitBoard);
		board.whitePieces = xorTwoBitBoards(board.whitePieces, toBitBoard);
		board.material -= KING_VALUE;
		break;

	case 3: // white advisor
		board.whiteAdvisors = xorTwoBitBoards(board.whiteAdvisors, toBitBoard);
		board.whitePieces = xorTwoBitBoards(board.whitePieces, toBitBoard);
		board.material -= ADVISOR_VALUE;
		break;

	case 4: // white elephant
		board.whiteElephants = xorTwoBitBoards(board.whiteElephants, toBitBoard);
		board.whitePieces = xorTwoBitBoards(board.whitePieces, toBitBoard);
		board.material -= ELEPHANT_VALUE;
		break;

	case 5: // white rook
		board.whiteRooks = xorTwoBitBoards(board.whiteRooks, toBitBoard);
		board.whitePieces = xorTwoBitBoards(board.whitePieces, toBitBoard);
		board.material -= ROOK_VALUE;
		break;

	case 6: // white cannon
		board.whiteCannons = xorTwoBitBoards(board.whiteCannons, toBitBoard);
		board.whitePieces = xorTwoBitBoards(board.whitePieces, toBitBoard);
		board.material -= CANNON_VALUE;
		break;

	case 7: // white horse
		board.whiteHorses = xorTwoBitBoards(board.whiteHorses, toBitBoard);
		board.whitePieces = xorTwoBitBoards(board.whitePieces, toBitBoard);
		board.material -= HORSE_VALUE;
		break;

	case 8: // black pawn
		board.blackPawns = xorTwoBitBoards(board.blackPawns, toBitBoard);
		board.blackPieces = xorTwoBitBoards(board.blackPieces, toBitBoard);
		board.material += PAWN_VALUE;
		break;

	case 9: // black king
		board.blackKing = xorTwoBitBoards(board.blackKing, toBitBoard);
		board.blackPieces = xorTwoBitBoards(board.blackPieces, toBitBoard);
		board.material += KING_VALUE;
		break;

	case 10: // black advisor
		board.blackAdvisors = xorTwoBitBoards(board.blackAdvisors, toBitBoard);
		board.blackPieces = xorTwoBitBoards(board.blackPieces, toBitBoard);
		board.material += ADVISOR_VALUE;
		break;

	case 11: // black elephant
		board.blackElephants = xorTwoBitBoards(board.blackElephants, toBitBoard);
		board.blackPieces = xorTwoBitBoards(board.blackPieces, toBitBoard);
		board.material += ELEPHANT_VALUE;
		break;

	case 12: // black rook
		board.blackRooks = xorTwoBitBoards(board.blackRooks, toBitBoard);
		board.blackPieces = xorTwoBitBoards(board.blackPieces, toBitBoard);
		board.material += ROOK_VALUE;
		break;

	case 13: // black cannon
		board.blackCannons = xorTwoBitBoards(board.blackCannons, toBitBoard);
		board.blackPieces = xorTwoBitBoards(board.blackPieces, toBitBoard);
		board.material += CANNON_VALUE;
		break;

	case 14: // black horse
		board.blackHorses = xorTwoBitBoards(board.blackHorses, toBitBoard);
		board.blackPieces = xorTwoBitBoards(board.blackPieces, toBitBoard);
		board.material += HORSE_VALUE;
		break;
	}
}

void unMakeCapture(unsigned int captured, unsigned int to)
{
	// deals with all captures
	BITBOARD toBitBoard = BITBOARDSET[to];

	switch (captured)
	{
	case 1: // white pawn:
		board.whitePawns = xorTwoBitBoards(board.whitePawns, toBitBoard);
		board.whitePieces = xorTwoBitBoards(board.whitePieces, toBitBoard);
		board.square[to] = WHITE_PAWN;
		board.material += PAWN_VALUE;
		break;

	case 2: // white king:
		board.whiteKing = xorTwoBitBoards(board.whiteKing, toBitBoard);
		board.whitePieces = xorTwoBitBoards(board.whitePieces, toBitBoard);
		board.square[to] = WHITE_KING;
		board.material += KING_VALUE;
		break;

	case 3: // white advisor:
		board.whiteAdvisors = xorTwoBitBoards(board.whiteAdvisors, toBitBoard);
		board.whitePieces = xorTwoBitBoards(board.whitePieces, toBitBoard);
		board.square[to] = WHITE_ADVISOR;
		board.material += ADVISOR_VALUE;
		break;

	case 4: // white elephant:
		board.whiteElephants = xorTwoBitBoards(board.whiteElephants, toBitBoard);
		board.whitePieces = xorTwoBitBoards(board.whitePieces, toBitBoard);
		board.square[to] = WHITE_ELEPHANT;
		board.material += ELEPHANT_VALUE;
		break;

	case 5: // white rook:
		board.whiteRooks = xorTwoBitBoards(board.whiteRooks, toBitBoard);
		board.whitePieces = xorTwoBitBoards(board.whitePieces, toBitBoard);
		board.square[to] = WHITE_ROOK;
		board.material += ROOK_VALUE;
		break;

	case 6: // white cannon:
		board.whiteCannons = xorTwoBitBoards(board.whiteCannons, toBitBoard);
		board.whitePieces = xorTwoBitBoards(board.whitePieces, toBitBoard);
		board.square[to] = WHITE_CANNON;
		board.material += CANNON_VALUE;
		break;

	case 7: // white horse:
		board.whiteHorses = xorTwoBitBoards(board.whiteHorses, toBitBoard);
		board.whitePieces = xorTwoBitBoards(board.whitePieces, toBitBoard);
		board.square[to] = WHITE_HORSE;
		board.material += HORSE_VALUE;
		break;

	case 8: // black pawn:
		board.blackPawns = xorTwoBitBoards(board.blackPawns, toBitBoard);
		board.blackPieces = xorTwoBitBoards(board.blackPieces, toBitBoard);
		board.square[to] = BLACK_PAWN;
		board.material -= PAWN_VALUE;
		break;

	case 9: // black king:
		board.blackKing = xorTwoBitBoards(board.blackKing, toBitBoard);
		board.blackPieces = xorTwoBitBoards(board.blackPieces, toBitBoard);
		board.square[to] = BLACK_KING;
		board.material -= KING_VALUE;
		break;

	case 10: // black advisor:
		board.blackAdvisors = xorTwoBitBoards(board.blackAdvisors, toBitBoard);
		board.blackPieces = xorTwoBitBoards(board.blackPieces, toBitBoard);
		board.square[to] = BLACK_ADVISOR;
		board.material -= ADVISOR_VALUE;
		break;

	case 11: // black elephant:
		board.blackElephants = xorTwoBitBoards(board.blackElephants, toBitBoard);
		board.blackPieces = xorTwoBitBoards(board.blackPieces, toBitBoard);
		board.square[to] = BLACK_ELEPHANT;
		board.material -= ELEPHANT_VALUE;
		break;

	case 12: // black rook:
		board.blackRooks = xorTwoBitBoards(board.blackRooks, toBitBoard);
		board.blackPieces = xorTwoBitBoards(board.blackPieces, toBitBoard);
		board.square[to] = BLACK_ROOK;
		board.material -= ROOK_VALUE;
		break;

	case 13: // black cannon:
		board.blackCannons = xorTwoBitBoards(board.blackCannons, toBitBoard);
		board.blackPieces = xorTwoBitBoards(board.blackPieces, toBitBoard);
		board.square[to] = BLACK_CANNON;
		board.material -= CANNON_VALUE;
		break;

	case 14: // black horse:
		board.blackHorses = xorTwoBitBoards(board.blackHorses, toBitBoard);
		board.blackPieces = xorTwoBitBoards(board.blackPieces, toBitBoard);
		board.square[to] = BLACK_HORSE;
		board.material -= HORSE_VALUE;
		break;
	}
}

BOOL isValidTextMove(char *userMove, MOVE *move)
{
	// Checks if userMove is valid by comparing it with moves from the move generator
	// If found valid, the move is returned

	unsigned char userFrom, userTo;
	int i;

	if (strlen(userMove) < 4)
	{
		move->moveInt = 0;
		return FALSE;
	}

	userFrom = userMove[0] - 97;
	userFrom += 9 * (userMove[1] - 48);
	userTo = userMove[2] - 97;
	userTo += 9 * (userMove[3] - 48);

	if (userFrom == userTo)
	{
		move->moveInt = 0;
		return FALSE;
	}

	for (i = board.moveBufLen[0]; i < board.moveBufLen[1]; i++)
	{
		if ((getFrom(board.moveBuffer[i]) == userFrom) && (getTosq(board.moveBuffer[i]) == userTo))
		{
			move->moveInt = board.moveBuffer[i].moveInt;
			return TRUE;
		}
	}

	move->moveInt = 0;
	return FALSE;
}

BOOL isOtherKingAttacked()
{
	// check to see if we are leaving our king in check
	if (board.nextMove)
	{
		return isAttacked(board.whiteKing, board.nextMove);
	}
	else
	{
		return isAttacked(board.blackKing, board.nextMove);
	}
}

BOOL isOwnKingAttacked()
{
	// check to see if we are leaving our king in check
	if (board.nextMove)
	{
		return isAttacked(board.blackKing, !board.nextMove);
	}
	else
	{
		return isAttacked(board.whiteKing, !board.nextMove);
	}
}

BOOL isTwoKingsFaceToFace()
{
	// check if white king and black king face to face
	// kings are not allowed to face each other directly. That is, if the two kings are on the same file,
	// at least one piece from either side must be in between, also on this file. A king will be captured if it moves into
	// the “line of sight” of the other king
	unsigned int whiteFrom = findFirstOneInBitBoard(board.whiteKing);
	unsigned int blackFrom = findFirstOneInBitBoard(board.blackKing);

	// the two kings are on the same file
	if (FILES[whiteFrom] == FILES[blackFrom])
	{
		BITBOARD whiteKingAttacks = ATTACKS_TOP[whiteFrom];
		BITBOARD blackKingAttacks = ATTACKS_BOTTOM[blackFrom];

		// The BITBOARD that all squares between two kings on the same file are set
		BITBOARD betweenTwoKings = andTwoBitBoards(whiteKingAttacks, blackKingAttacks);

		// no piece is between the two kings
		if (isAllZeroBit(andTwoBitBoards(betweenTwoKings, board.occupiedSquares)))
			return TRUE;
	}

	return FALSE;
}

BOOL isAttacked(BITBOARD targetBitBoard, unsigned char fromSide)
{

	//  ===========================================================================
	//  isAttacked is used mainly as a move legality test to see if targetBitBoard is
	//  attacked by white or black.
	//  Returns true at the first attack found, and returns false if no attack is found.
	//  ===========================================================================

	int toSquare;
	BITBOARD tempTargetBitBoard = targetBitBoard;
	BITBOARD tempPiece, tempMove;
	int from, to;

	if (fromSide) // test for attacks from BLACK to targetBitBoard
	{
		while (!isAllZeroBit(tempTargetBitBoard))
		{
			toSquare = findFirstOneInBitBoard(tempTargetBitBoard);

			// there's at least a black pawn can attack to toSqure
			if (!isAllZeroBit(andTwoBitBoards(board.blackPawns, BLACK_PAWN_ATTACKS[toSquare]))) return TRUE;

			// there's at least a black advisor can attack to toSqure
			if (!isAllZeroBit(andTwoBitBoards(board.blackAdvisors, ADVISOR_ATTACKS[toSquare]))) return TRUE;

			//the black king can attack to toSqure
			if (!isAllZeroBit(andTwoBitBoards(board.blackKing, KING_ATTACKS[toSquare]))) return TRUE;

			// Check if there is any black horses can attack to toSqure
			tempPiece = board.blackHorses;
			while (!isAllZeroBit(tempPiece))
			{
				from = findFirstOneInBitBoard(tempPiece);

				clearBitBoard(&tempMove);
				if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, HORSE_OBSTRUCTS[from][0])))
					tempMove = orTwoBitBoards(tempMove, HORSE_ATTACKS[from][0]);
				if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, HORSE_OBSTRUCTS[from][1])))
					tempMove = orTwoBitBoards(tempMove, HORSE_ATTACKS[from][1]);
				if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, HORSE_OBSTRUCTS[from][2])))
					tempMove = orTwoBitBoards(tempMove, HORSE_ATTACKS[from][2]);
				if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, HORSE_OBSTRUCTS[from][3])))
					tempMove = orTwoBitBoards(tempMove, HORSE_ATTACKS[from][3]);

				tempMove = andTwoBitBoards(tempMove, tempTargetBitBoard);
				while (!isAllZeroBit(tempMove))
				{
					to = findFirstOneInBitBoard(tempMove);
					if (to == toSquare)
						return TRUE;
					tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
				}
				tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
			}

			// Check if there is any black elephants can attack to toSqure
			tempPiece = board.blackElephants;
			while (!isAllZeroBit(tempPiece))
			{
				from = findFirstOneInBitBoard(tempPiece);
				clearBitBoard(&tempMove);
				if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, ELEPHANT_OBSTRUCTS[from][0])))
					tempMove = orTwoBitBoards(tempMove, ELEPHANT_ATTACKS[from][0]);
				if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, ELEPHANT_OBSTRUCTS[from][1])))
					tempMove = orTwoBitBoards(tempMove, ELEPHANT_ATTACKS[from][1]);
				if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, ELEPHANT_OBSTRUCTS[from][2])))
					tempMove = orTwoBitBoards(tempMove, ELEPHANT_ATTACKS[from][2]);
				if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, ELEPHANT_OBSTRUCTS[from][3])))
					tempMove = orTwoBitBoards(tempMove, ELEPHANT_ATTACKS[from][3]);
				tempMove = andTwoBitBoards(tempMove, tempTargetBitBoard);
				while (!isAllZeroBit(tempMove))
				{
					to = findFirstOneInBitBoard(tempMove);
					if (to == toSquare)
						return TRUE;
					tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
				}
				tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
			}

			// Check if there is any black rooks can attack to toSqure
			BITBOARD rookAttacks, rookRightAttacks, rookTopAttacks, rookLeftAttacks, rookBottomAttacks;
			tempPiece = board.blackRooks;
			while (!isAllZeroBit(tempPiece))
			{
				from = findFirstOneInBitBoard(tempPiece);

				// We do this because the first piece will stop the rook moving to the right.
				rookRightAttacks = andTwoBitBoards(ATTACKS_RIGHT[from], board.occupiedSquares);
				// Because the first piece will stop the rook, we need to fill in all the squares to the right of the piece
				if (!isAllZeroBit(rookRightAttacks))
					rookRightAttacks = ATTACKS_RIGHT[findFirstOneInBitBoard(rookRightAttacks)];
				// To get the squares where the rook can move to, we exclusive OR the board with ATTACKS_RIGHT[from]
				rookRightAttacks = xorTwoBitBoards(rookRightAttacks, ATTACKS_RIGHT[from]);

				// We do this because the first piece will stop the rook moving on the top.
				rookTopAttacks = andTwoBitBoards(ATTACKS_TOP[from], board.occupiedSquares);
				// Because the first piece will stop the rook, we need to fill in all the squares on the top of the piece
				if (!isAllZeroBit(rookTopAttacks))
					rookTopAttacks = ATTACKS_TOP[findFirstOneInBitBoard(rookTopAttacks)];
				// To get the squares where the rook can move to, we exclusive OR the board with ATTACKS_TOP[from]
				rookTopAttacks = xorTwoBitBoards(rookTopAttacks, ATTACKS_TOP[from]);

				// We do this because the first piece will stop the rook moving to the left.
				rookLeftAttacks = andTwoBitBoards(ATTACKS_LEFT[from], board.occupiedSquares);
				// Because the first piece will stop the rook, we need to fill in all the squares to the left of the piece
				if (!isAllZeroBit(rookLeftAttacks))
					rookLeftAttacks = ATTACKS_LEFT[findLastOneInBitBoard(rookLeftAttacks)];
				// To get the squares where the rook can move to, we exclusive OR the board with ATTACKS_LEFT[from]
				rookLeftAttacks = xorTwoBitBoards(rookLeftAttacks, ATTACKS_LEFT[from]);

				// We do this because the first piece will stop the rook moving on the bottom.
				rookBottomAttacks = andTwoBitBoards(ATTACKS_BOTTOM[from], board.occupiedSquares);
				// Because the first piece will stop the rook, we need to fill in all the squares on the bottom of the piece
				if (!isAllZeroBit(rookBottomAttacks))
					rookBottomAttacks = ATTACKS_BOTTOM[findLastOneInBitBoard(rookBottomAttacks)];
				// To get the squares where the rook can move to, we exclusive OR the board with ATTACKS_BOTTOM[from]
				rookBottomAttacks = xorTwoBitBoards(rookBottomAttacks, ATTACKS_BOTTOM[from]);

				rookAttacks = orTwoBitBoards(rookRightAttacks, rookTopAttacks);
				rookAttacks = orTwoBitBoards(rookAttacks, rookLeftAttacks);
				rookAttacks = orTwoBitBoards(rookAttacks, rookBottomAttacks);

				tempMove = andTwoBitBoards(rookAttacks, tempTargetBitBoard);
				while (!isAllZeroBit(tempMove))
				{
					to = findFirstOneInBitBoard(tempMove);
					if (to == toSquare)
						return TRUE;
					tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
				}
				tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
			}

			// Check if there is any black cannons can attack to toSqure
			BITBOARD cannonAttacks, cannonRightAttacks, cannonTopAttacks, cannonLeftAttacks, cannonBottomAttacks;
			BITBOARD rightTempBB, topTempBB, leftTempBB, bottomTempBB;
			tempPiece = board.blackCannons;
			while (!isAllZeroBit(tempPiece))
			{
				from = findFirstOneInBitBoard(tempPiece);

				clearBitBoard(&rightTempBB);
				clearBitBoard(&topTempBB);
				clearBitBoard(&leftTempBB);
				clearBitBoard(&bottomTempBB);

				// We do this because the first piece will stop the rook moving to the right.
				cannonRightAttacks = andTwoBitBoards(ATTACKS_RIGHT[from], board.occupiedSquares);
				// Because the first piece will stop the cannon, we need to fill in all the squares to the right of the piece
				if (!isAllZeroBit(cannonRightAttacks))
				{
					unsigned int firstOne = findFirstOneInBitBoard(cannonRightAttacks);
					cannonRightAttacks = ATTACKS_RIGHT[firstOne];
					cannonRightAttacks = orTwoBitBoards(cannonRightAttacks, BITBOARDSET[firstOne]);

					rightTempBB = andTwoBitBoards(ATTACKS_RIGHT[firstOne], board.whitePieces);
					if (!isAllZeroBit(rightTempBB))
						rightTempBB = BITBOARDSET[findFirstOneInBitBoard(rightTempBB)];
				}
				// To get the squares where the cannon can move to, we exclusive OR the board with ATTACKS_RIGHT[from]
				cannonRightAttacks = xorTwoBitBoards(cannonRightAttacks, ATTACKS_RIGHT[from]);
				// Eat if possible
				cannonRightAttacks = orTwoBitBoards(cannonRightAttacks, rightTempBB);


				// We do this because the first piece will stop the cannon moving on the top.
				cannonTopAttacks = andTwoBitBoards(ATTACKS_TOP[from], board.occupiedSquares);
				// Because the first piece will stop the cannon, we need to fill in all the squares on the top of the piece
				if (!isAllZeroBit(cannonTopAttacks))
				{
					unsigned int firstOne = findFirstOneInBitBoard(cannonTopAttacks);
					cannonTopAttacks = ATTACKS_TOP[firstOne];
					cannonTopAttacks = orTwoBitBoards(cannonTopAttacks, BITBOARDSET[firstOne]);

					topTempBB = andTwoBitBoards(ATTACKS_TOP[firstOne], board.whitePieces);
					if (!isAllZeroBit(topTempBB))
						topTempBB = BITBOARDSET[findFirstOneInBitBoard(topTempBB)];
				}
				// To get the squares where the cannon can move to, we exclusive OR the board with ATTACKS_TOP[from]
				cannonTopAttacks = xorTwoBitBoards(cannonTopAttacks, ATTACKS_TOP[from]);
				// Eat if possible
				cannonTopAttacks = orTwoBitBoards(cannonTopAttacks, topTempBB);


				// We do this because the first piece will stop the cannon moving to the left.
				cannonLeftAttacks = andTwoBitBoards(ATTACKS_LEFT[from], board.occupiedSquares);
				// Because the first piece will stop the cannon, we need to fill in all the squares to the left of the piece
				if (!isAllZeroBit(cannonLeftAttacks))
				{
					unsigned int lastOne = findLastOneInBitBoard(cannonLeftAttacks);
					cannonLeftAttacks = ATTACKS_LEFT[lastOne];
					cannonLeftAttacks = orTwoBitBoards(cannonLeftAttacks, BITBOARDSET[lastOne]);

					leftTempBB = andTwoBitBoards(ATTACKS_LEFT[lastOne], board.whitePieces);
					if (!isAllZeroBit(leftTempBB))
						leftTempBB = BITBOARDSET[findLastOneInBitBoard(leftTempBB)];
				}
				// To get the squares where the cannon can move to, we exclusive OR the board with ATTACKS_LEFT[from]
				cannonLeftAttacks = xorTwoBitBoards(cannonLeftAttacks, ATTACKS_LEFT[from]);
				// Eat if possible
				cannonLeftAttacks = orTwoBitBoards(cannonLeftAttacks, leftTempBB);


				// We do this because the first piece will stop the cannon moving on the bottom.
				cannonBottomAttacks = andTwoBitBoards(ATTACKS_BOTTOM[from], board.occupiedSquares);
				// Because the first piece will stop the cannon, we need to fill in all the squares on the bottom of the piece
				if (!isAllZeroBit(cannonBottomAttacks))
				{
					unsigned int lastOne = findLastOneInBitBoard(cannonBottomAttacks);
					cannonBottomAttacks = ATTACKS_BOTTOM[lastOne];
					cannonBottomAttacks = orTwoBitBoards(cannonBottomAttacks, BITBOARDSET[lastOne]);

					bottomTempBB = andTwoBitBoards(ATTACKS_BOTTOM[lastOne], board.whitePieces);
					if (!isAllZeroBit(bottomTempBB))
						bottomTempBB = BITBOARDSET[findLastOneInBitBoard(bottomTempBB)];
				}
				// To get the squares where the cannon can move to, we exclusive OR the board with ATTACKS_BOTTOM[from]
				cannonBottomAttacks = xorTwoBitBoards(cannonBottomAttacks, ATTACKS_BOTTOM[from]);
				// Eat if possible
				cannonBottomAttacks = orTwoBitBoards(cannonBottomAttacks, bottomTempBB);

				cannonAttacks = orTwoBitBoards(cannonRightAttacks, cannonTopAttacks);
				cannonAttacks = orTwoBitBoards(cannonAttacks, cannonLeftAttacks);
				cannonAttacks = orTwoBitBoards(cannonAttacks, cannonBottomAttacks);

				tempMove = andTwoBitBoards(cannonAttacks, tempTargetBitBoard);
				while (!isAllZeroBit(tempMove))
				{
					to = findFirstOneInBitBoard(tempMove);
					if (to == toSquare)
						return TRUE;
					tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
				}
				tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
			}

			tempTargetBitBoard = xorTwoBitBoards(tempTargetBitBoard, BITBOARDSET[toSquare]);
		}
	}
	else // test for attacks from WHITE to targetBitmap
	{
		while (!isAllZeroBit(tempTargetBitBoard))
		{
			toSquare = findFirstOneInBitBoard(tempTargetBitBoard);

			// there's at least a white pawn can attack to toSqure
			if (!isAllZeroBit(andTwoBitBoards(board.whitePawns, WHITE_PAWN_ATTACKS[toSquare]))) return TRUE;

			// there's at least a white advisor can attack to toSqure
			if (!isAllZeroBit(andTwoBitBoards(board.whiteAdvisors, ADVISOR_ATTACKS[toSquare]))) return TRUE;

			//the white king can attack to toSqure
			if (!isAllZeroBit(andTwoBitBoards(board.whiteKing, KING_ATTACKS[toSquare]))) return TRUE;

			// Check if there is any white horses can attack to toSqure
			tempPiece = board.whiteHorses;
			while (!isAllZeroBit(tempPiece))
			{
				from = findFirstOneInBitBoard(tempPiece);

				clearBitBoard(&tempMove);
				if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, HORSE_OBSTRUCTS[from][0])))
					tempMove = orTwoBitBoards(tempMove, HORSE_ATTACKS[from][0]);
				if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, HORSE_OBSTRUCTS[from][1])))
					tempMove = orTwoBitBoards(tempMove, HORSE_ATTACKS[from][1]);
				if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, HORSE_OBSTRUCTS[from][2])))
					tempMove = orTwoBitBoards(tempMove, HORSE_ATTACKS[from][2]);
				if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, HORSE_OBSTRUCTS[from][3])))
					tempMove = orTwoBitBoards(tempMove, HORSE_ATTACKS[from][3]);

				tempMove = andTwoBitBoards(tempMove, tempTargetBitBoard);
				while (!isAllZeroBit(tempMove))
				{
					to = findFirstOneInBitBoard(tempMove);
					if (to == toSquare)
						return TRUE;
					tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
				}
				tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
			}

			// Check if there is any white elephants can attack to toSqure
			tempPiece = board.whiteElephants;
			while (!isAllZeroBit(tempPiece))
			{
				from = findFirstOneInBitBoard(tempPiece);
				clearBitBoard(&tempMove);
				if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, ELEPHANT_OBSTRUCTS[from][0])))
					tempMove = orTwoBitBoards(tempMove, ELEPHANT_ATTACKS[from][0]);
				if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, ELEPHANT_OBSTRUCTS[from][1])))
					tempMove = orTwoBitBoards(tempMove, ELEPHANT_ATTACKS[from][1]);
				if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, ELEPHANT_OBSTRUCTS[from][2])))
					tempMove = orTwoBitBoards(tempMove, ELEPHANT_ATTACKS[from][2]);
				if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, ELEPHANT_OBSTRUCTS[from][3])))
					tempMove = orTwoBitBoards(tempMove, ELEPHANT_ATTACKS[from][3]);
				tempMove = andTwoBitBoards(tempMove, tempTargetBitBoard);
				while (!isAllZeroBit(tempMove))
				{
					to = findFirstOneInBitBoard(tempMove);
					if (to == toSquare)
						return TRUE;
					tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
				}
				tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
			}

			// Check if there is any white rooks can attack to toSqure
			BITBOARD rookAttacks, rookRightAttacks, rookTopAttacks, rookLeftAttacks, rookBottomAttacks;
			tempPiece = board.whiteRooks;
			while (!isAllZeroBit(tempPiece))
			{
				from = findFirstOneInBitBoard(tempPiece);

				// We do this because the first piece will stop the rook moving to the right.
				rookRightAttacks = andTwoBitBoards(ATTACKS_RIGHT[from], board.occupiedSquares);
				// Because the first piece will stop the rook, we need to fill in all the squares to the right of the piece
				if (!isAllZeroBit(rookRightAttacks))
					rookRightAttacks = ATTACKS_RIGHT[findFirstOneInBitBoard(rookRightAttacks)];
				// To get the squares where the rook can move to, we exclusive OR the board with ATTACKS_RIGHT[from]
				rookRightAttacks = xorTwoBitBoards(rookRightAttacks, ATTACKS_RIGHT[from]);

				// We do this because the first piece will stop the rook moving on the top.
				rookTopAttacks = andTwoBitBoards(ATTACKS_TOP[from], board.occupiedSquares);
				// Because the first piece will stop the rook, we need to fill in all the squares on the top of the piece
				if (!isAllZeroBit(rookTopAttacks))
					rookTopAttacks = ATTACKS_TOP[findFirstOneInBitBoard(rookTopAttacks)];
				// To get the squares where the rook can move to, we exclusive OR the board with ATTACKS_TOP[from]
				rookTopAttacks = xorTwoBitBoards(rookTopAttacks, ATTACKS_TOP[from]);

				// We do this because the first piece will stop the rook moving to the left.
				rookLeftAttacks = andTwoBitBoards(ATTACKS_LEFT[from], board.occupiedSquares);
				// Because the first piece will stop the rook, we need to fill in all the squares to the left of the piece
				if (!isAllZeroBit(rookLeftAttacks))
					rookLeftAttacks = ATTACKS_LEFT[findLastOneInBitBoard(rookLeftAttacks)];
				// To get the squares where the rook can move to, we exclusive OR the board with ATTACKS_LEFT[from]
				rookLeftAttacks = xorTwoBitBoards(rookLeftAttacks, ATTACKS_LEFT[from]);

				// We do this because the first piece will stop the rook moving on the bottom.
				rookBottomAttacks = andTwoBitBoards(ATTACKS_BOTTOM[from], board.occupiedSquares);
				// Because the first piece will stop the rook, we need to fill in all the squares on the bottom of the piece
				if (!isAllZeroBit(rookBottomAttacks))
					rookBottomAttacks = ATTACKS_BOTTOM[findLastOneInBitBoard(rookBottomAttacks)];
				// To get the squares where the rook can move to, we exclusive OR the board with ATTACKS_BOTTOM[from]
				rookBottomAttacks = xorTwoBitBoards(rookBottomAttacks, ATTACKS_BOTTOM[from]);

				rookAttacks = orTwoBitBoards(rookRightAttacks, rookTopAttacks);
				rookAttacks = orTwoBitBoards(rookAttacks, rookLeftAttacks);
				rookAttacks = orTwoBitBoards(rookAttacks, rookBottomAttacks);

				tempMove = andTwoBitBoards(rookAttacks, tempTargetBitBoard);
				while (!isAllZeroBit(tempMove))
				{
					to = findFirstOneInBitBoard(tempMove);
					if (to == toSquare)
						return TRUE;
					tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
				}
				tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
			}

			// Check if there is any white cannons can attack to toSqure
			BITBOARD cannonAttacks, cannonRightAttacks, cannonTopAttacks, cannonLeftAttacks, cannonBottomAttacks;
			BITBOARD rightTempBB, topTempBB, leftTempBB, bottomTempBB;
			tempPiece = board.whiteCannons;
			while (!isAllZeroBit(tempPiece))
			{
				from = findFirstOneInBitBoard(tempPiece);

				clearBitBoard(&rightTempBB);
				clearBitBoard(&topTempBB);
				clearBitBoard(&leftTempBB);
				clearBitBoard(&bottomTempBB);

				// We do this because the first piece will stop the rook moving to the right.
				cannonRightAttacks = andTwoBitBoards(ATTACKS_RIGHT[from], board.occupiedSquares);
				// Because the first piece will stop the cannon, we need to fill in all the squares to the right of the piece
				if (!isAllZeroBit(cannonRightAttacks))
				{
					unsigned int firstOne = findFirstOneInBitBoard(cannonRightAttacks);
					cannonRightAttacks = ATTACKS_RIGHT[firstOne];
					cannonRightAttacks = orTwoBitBoards(cannonRightAttacks, BITBOARDSET[firstOne]);

					rightTempBB = andTwoBitBoards(ATTACKS_RIGHT[firstOne], board.blackPieces);
					if (!isAllZeroBit(rightTempBB))
						rightTempBB = BITBOARDSET[findFirstOneInBitBoard(rightTempBB)];
				}
				// To get the squares where the cannon can move to, we exclusive OR the board with ATTACKS_RIGHT[from]
				cannonRightAttacks = xorTwoBitBoards(cannonRightAttacks, ATTACKS_RIGHT[from]);
				// Eat if possible
				cannonRightAttacks = orTwoBitBoards(cannonRightAttacks, rightTempBB);


				// We do this because the first piece will stop the cannon moving on the top.
				cannonTopAttacks = andTwoBitBoards(ATTACKS_TOP[from], board.occupiedSquares);
				// Because the first piece will stop the cannon, we need to fill in all the squares on the top of the piece
				if (!isAllZeroBit(cannonTopAttacks))
				{
					unsigned int firstOne = findFirstOneInBitBoard(cannonTopAttacks);
					cannonTopAttacks = ATTACKS_TOP[firstOne];
					cannonTopAttacks = orTwoBitBoards(cannonTopAttacks, BITBOARDSET[firstOne]);

					topTempBB = andTwoBitBoards(ATTACKS_TOP[firstOne], board.blackPieces);
					if (!isAllZeroBit(topTempBB))
						topTempBB = BITBOARDSET[findFirstOneInBitBoard(topTempBB)];
				}
				// To get the squares where the cannon can move to, we exclusive OR the board with ATTACKS_TOP[from]
				cannonTopAttacks = xorTwoBitBoards(cannonTopAttacks, ATTACKS_TOP[from]);
				// Eat if possible
				cannonTopAttacks = orTwoBitBoards(cannonTopAttacks, topTempBB);


				// We do this because the first piece will stop the cannon moving to the left.
				cannonLeftAttacks = andTwoBitBoards(ATTACKS_LEFT[from], board.occupiedSquares);
				// Because the first piece will stop the cannon, we need to fill in all the squares to the left of the piece
				if (!isAllZeroBit(cannonLeftAttacks))
				{
					unsigned int lastOne = findLastOneInBitBoard(cannonLeftAttacks);
					cannonLeftAttacks = ATTACKS_LEFT[lastOne];
					cannonLeftAttacks = orTwoBitBoards(cannonLeftAttacks, BITBOARDSET[lastOne]);

					leftTempBB = andTwoBitBoards(ATTACKS_LEFT[lastOne], board.blackPieces);
					if (!isAllZeroBit(leftTempBB))
						leftTempBB = BITBOARDSET[findLastOneInBitBoard(leftTempBB)];
				}
				// To get the squares where the cannon can move to, we exclusive OR the board with ATTACKS_LEFT[from]
				cannonLeftAttacks = xorTwoBitBoards(cannonLeftAttacks, ATTACKS_LEFT[from]);
				// Eat if possible
				cannonLeftAttacks = orTwoBitBoards(cannonLeftAttacks, leftTempBB);


				// We do this because the first piece will stop the cannon moving on the bottom.
				cannonBottomAttacks = andTwoBitBoards(ATTACKS_BOTTOM[from], board.occupiedSquares);
				// Because the first piece will stop the cannon, we need to fill in all the squares on the bottom of the piece
				if (!isAllZeroBit(cannonBottomAttacks))
				{
					unsigned int lastOne = findLastOneInBitBoard(cannonBottomAttacks);
					cannonBottomAttacks = ATTACKS_BOTTOM[lastOne];
					cannonBottomAttacks = orTwoBitBoards(cannonBottomAttacks, BITBOARDSET[lastOne]);

					bottomTempBB = andTwoBitBoards(ATTACKS_BOTTOM[lastOne], board.blackPieces);
					if (!isAllZeroBit(bottomTempBB))
						bottomTempBB = BITBOARDSET[findLastOneInBitBoard(bottomTempBB)];
				}
				// To get the squares where the cannon can move to, we exclusive OR the board with ATTACKS_BOTTOM[from]
				cannonBottomAttacks = xorTwoBitBoards(cannonBottomAttacks, ATTACKS_BOTTOM[from]);
				// Eat if possible
				cannonBottomAttacks = orTwoBitBoards(cannonBottomAttacks, bottomTempBB);

				cannonAttacks = orTwoBitBoards(cannonRightAttacks, cannonTopAttacks);
				cannonAttacks = orTwoBitBoards(cannonAttacks, cannonLeftAttacks);
				cannonAttacks = orTwoBitBoards(cannonAttacks, cannonBottomAttacks);

				tempMove = andTwoBitBoards(cannonAttacks, tempTargetBitBoard);
				while (!isAllZeroBit(tempMove))
				{
					to = findFirstOneInBitBoard(tempMove);
					if (to == toSquare)
						return TRUE;
					tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
				}
				tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
			}

			tempTargetBitBoard = xorTwoBitBoards(tempTargetBitBoard, BITBOARDSET[toSquare]);
		}
	}

	return FALSE;
}



// binary: 1111 1111 1111 1111 1111 1111 1000 0000
// hex   : ffffff80
// this constant is used to clear the 'from' bitfield of a move
// by operating moveInt & 0xffffff80
const unsigned int CLEAR_FROM = 0xffffff80;

// binary: 1111 1111 1111 1111 1100 0000 0111 1111
// hex   : ffffc07f
// this constant is used to clear the 'tosq' bitfield of a move
// by operating moveInt & ffffc07f
const unsigned int CLEAR_TOSQ = 0xffffc07f;

// binary: 1111 1111 1111 1100 0011 1111 1111 1111
// hex   : fffc3fff
// this constant is used to clear the 'piec' bitfield of a move
// by operating moveInt & fffc3fff
const unsigned int CLEAR_PIEC = 0xfffc3fff;

// binary: 1111 1111 1100 0011 1111 1111 1111 1111
// hex   : ffc3ffff
// this constant is used to clear the 'piec' bitfield of a move
// by operating moveInt & ffc3ffff
const unsigned int CLEAR_CAPT = 0xffc3ffff;

// binary: 0000 0000 0000 0000 0000 0000 0111 1111
// hex:    0000007f
const unsigned int SEVEN_RIGHT_MOST = 0x0000007f;

// binary: 0000 0000 0000 0000 0000 0000 0000 1111
// hex:    0000000f
const unsigned int FOUR_RIGHT_MOST = 0x0000000f;

void setFrom(MOVE*  m_move, unsigned int m_from)
{
	m_move->moveInt &= CLEAR_FROM;
	m_move->moveInt |= (m_from & SEVEN_RIGHT_MOST);
	return;
}

void setTosq(MOVE*  m_move, unsigned int m_tosq)
{
	m_move->moveInt &= CLEAR_TOSQ;
	m_move->moveInt |= (m_tosq & SEVEN_RIGHT_MOST) << 7;
	return;
}

void setPiec(MOVE*  m_move, unsigned int m_piec)
{
	m_move->moveInt &= CLEAR_PIEC;
	m_move->moveInt |= (m_piec & FOUR_RIGHT_MOST) << 14;
	return;
}

void setCapt(MOVE*  m_move, unsigned int m_capt)
{
	m_move->moveInt &= CLEAR_CAPT;
	m_move->moveInt |= (m_capt & FOUR_RIGHT_MOST) << 18;
	return;
}

unsigned int getFrom(MOVE  m_move)
{
	return m_move.moveInt & SEVEN_RIGHT_MOST;
}

unsigned int getTosq(MOVE  m_move)
{
	return (m_move.moveInt >> 7) & SEVEN_RIGHT_MOST;
}

unsigned int getPiec(MOVE  m_move)
{
	return (m_move.moveInt >> 14) & FOUR_RIGHT_MOST;
}

unsigned int getCapt(MOVE  m_move)
{
	return (m_move.moveInt >> 18) & FOUR_RIGHT_MOST;
}

void clear(MOVE* m_move)
{
	m_move->moveInt = 0;
}

void displayMove(MOVE move)
{
	unsigned int from, to;
	from = getFrom(move);
	to = getTosq(move);

	printf("%s%s", SQUARENAME[from], SQUARENAME[to]);
	fflush(stdout);
}



unsigned int movegen(unsigned int index)
{
	// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	// This is pseudo-legal bitboard move generator,
	// using magic multiplication instead of rotated bitboards.
	// There is no check if a move leaves the king in check
	// The first free location in moveBuffer[] is supplied in index,
	// and the new first free location is returned
	// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

	unsigned int from, to;
	BITBOARD tempPiece, tempMove;
	BITBOARD targetBitBoard;
	MOVE move;

	clear(&move);

	// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	// Black to move
	// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	if (board.nextMove)
	{
		// we cannot capture one of our own pieces!
		targetBitBoard = notBitBoard(board.blackPieces);

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// Black horses
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		setPiec(&move, BLACK_HORSE);
		tempPiece = board.blackHorses;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			clearBitBoard(&tempMove);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, HORSE_OBSTRUCTS[from][0])))
				tempMove = orTwoBitBoards(tempMove, HORSE_ATTACKS[from][0]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, HORSE_OBSTRUCTS[from][1])))
				tempMove = orTwoBitBoards(tempMove, HORSE_ATTACKS[from][1]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, HORSE_OBSTRUCTS[from][2])))
				tempMove = orTwoBitBoards(tempMove, HORSE_ATTACKS[from][2]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, HORSE_OBSTRUCTS[from][3])))
				tempMove = orTwoBitBoards(tempMove, HORSE_ATTACKS[from][3]);

			tempMove = andTwoBitBoards(tempMove, targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// Black elephants
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		clear(&move);
		setPiec(&move, BLACK_ELEPHANT);
		tempPiece = board.blackElephants;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);
			clearBitBoard(&tempMove);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, ELEPHANT_OBSTRUCTS[from][0])))
				tempMove = orTwoBitBoards(tempMove, ELEPHANT_ATTACKS[from][0]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, ELEPHANT_OBSTRUCTS[from][1])))
				tempMove = orTwoBitBoards(tempMove, ELEPHANT_ATTACKS[from][1]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, ELEPHANT_OBSTRUCTS[from][2])))
				tempMove = orTwoBitBoards(tempMove, ELEPHANT_ATTACKS[from][2]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, ELEPHANT_OBSTRUCTS[from][3])))
				tempMove = orTwoBitBoards(tempMove, ELEPHANT_ATTACKS[from][3]);
			tempMove = andTwoBitBoards(tempMove, targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// Black advisors
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		clear(&move);
		setPiec(&move, BLACK_ADVISOR);
		tempPiece = board.blackAdvisors;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			tempMove = andTwoBitBoards(ADVISOR_ATTACKS[from], targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// Black king
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		clear(&move);
		setPiec(&move, BLACK_KING);
		tempPiece = board.blackKing;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			tempMove = andTwoBitBoards(KING_ATTACKS[from], targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// Black pawns
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		clear(&move);
		setPiec(&move, BLACK_PAWN);
		tempPiece = board.blackPawns;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			tempMove = andTwoBitBoards(BLACK_PAWN_ATTACKS[from], targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// Black rooks
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		BITBOARD rookAttacks, rookRightAttacks, rookTopAttacks, rookLeftAttacks, rookBottomAttacks;
		clear(&move);
		setPiec(&move, BLACK_ROOK);
		tempPiece = board.blackRooks;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			// We do this because the first piece will stop the rook moving to the right.
			rookRightAttacks = andTwoBitBoards(ATTACKS_RIGHT[from], board.occupiedSquares);
			// Because the first piece will stop the rook, we need to fill in all the squares to the right of the piece
			if (!isAllZeroBit(rookRightAttacks))
				rookRightAttacks = ATTACKS_RIGHT[findFirstOneInBitBoard(rookRightAttacks)];
			// To get the squares where the rook can move to, we exclusive OR the board with ATTACKS_RIGHT[from]
			rookRightAttacks = xorTwoBitBoards(rookRightAttacks, ATTACKS_RIGHT[from]);

			// We do this because the first piece will stop the rook moving on the top.
			rookTopAttacks = andTwoBitBoards(ATTACKS_TOP[from], board.occupiedSquares);
			// Because the first piece will stop the rook, we need to fill in all the squares on the top of the piece
			if (!isAllZeroBit(rookTopAttacks))
				rookTopAttacks = ATTACKS_TOP[findFirstOneInBitBoard(rookTopAttacks)];
			// To get the squares where the rook can move to, we exclusive OR the board with ATTACKS_TOP[from]
			rookTopAttacks = xorTwoBitBoards(rookTopAttacks, ATTACKS_TOP[from]);

			// We do this because the first piece will stop the rook moving to the left.
			rookLeftAttacks = andTwoBitBoards(ATTACKS_LEFT[from], board.occupiedSquares);
			// Because the first piece will stop the rook, we need to fill in all the squares to the left of the piece
			if (!isAllZeroBit(rookLeftAttacks))
				rookLeftAttacks = ATTACKS_LEFT[findLastOneInBitBoard(rookLeftAttacks)];
			// To get the squares where the rook can move to, we exclusive OR the board with ATTACKS_LEFT[from]
			rookLeftAttacks = xorTwoBitBoards(rookLeftAttacks, ATTACKS_LEFT[from]);

			// We do this because the first piece will stop the rook moving on the bottom.
			rookBottomAttacks = andTwoBitBoards(ATTACKS_BOTTOM[from], board.occupiedSquares);
			// Because the first piece will stop the rook, we need to fill in all the squares on the bottom of the piece
			if (!isAllZeroBit(rookBottomAttacks))
				rookBottomAttacks = ATTACKS_BOTTOM[findLastOneInBitBoard(rookBottomAttacks)];
			// To get the squares where the rook can move to, we exclusive OR the board with ATTACKS_BOTTOM[from]
			rookBottomAttacks = xorTwoBitBoards(rookBottomAttacks, ATTACKS_BOTTOM[from]);

			rookAttacks = orTwoBitBoards(rookRightAttacks, rookTopAttacks);
			rookAttacks = orTwoBitBoards(rookAttacks, rookLeftAttacks);
			rookAttacks = orTwoBitBoards(rookAttacks, rookBottomAttacks);

			tempMove = andTwoBitBoards(rookAttacks, targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// Black cannons
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		BITBOARD cannonAttacks, cannonRightAttacks, cannonTopAttacks, cannonLeftAttacks, cannonBottomAttacks;
		BITBOARD rightTempBB, topTempBB, leftTempBB, bottomTempBB;
		clear(&move);
		setPiec(&move, BLACK_CANNON);
		tempPiece = board.blackCannons;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			clearBitBoard(&rightTempBB);
			clearBitBoard(&topTempBB);
			clearBitBoard(&leftTempBB);
			clearBitBoard(&bottomTempBB);

			// We do this because the first piece will stop the rook moving to the right.
			cannonRightAttacks = andTwoBitBoards(ATTACKS_RIGHT[from], board.occupiedSquares);
			// Because the first piece will stop the cannon, we need to fill in all the squares to the right of the piece
			if (!isAllZeroBit(cannonRightAttacks))
			{
				unsigned int firstOne = findFirstOneInBitBoard(cannonRightAttacks);
				cannonRightAttacks = ATTACKS_RIGHT[firstOne];
				cannonRightAttacks = orTwoBitBoards(cannonRightAttacks, BITBOARDSET[firstOne]);

				rightTempBB = andTwoBitBoards(ATTACKS_RIGHT[firstOne], board.whitePieces);
				if (!isAllZeroBit(rightTempBB))
					rightTempBB = BITBOARDSET[findFirstOneInBitBoard(rightTempBB)];
			}
			// To get the squares where the cannon can move to, we exclusive OR the board with ATTACKS_RIGHT[from]
			cannonRightAttacks = xorTwoBitBoards(cannonRightAttacks, ATTACKS_RIGHT[from]);
			// Eat if possible
			cannonRightAttacks = orTwoBitBoards(cannonRightAttacks, rightTempBB);


			// We do this because the first piece will stop the cannon moving on the top.
			cannonTopAttacks = andTwoBitBoards(ATTACKS_TOP[from], board.occupiedSquares);
			// Because the first piece will stop the cannon, we need to fill in all the squares on the top of the piece
			if (!isAllZeroBit(cannonTopAttacks))
			{
				unsigned int firstOne = findFirstOneInBitBoard(cannonTopAttacks);
				cannonTopAttacks = ATTACKS_TOP[firstOne];
				cannonTopAttacks = orTwoBitBoards(cannonTopAttacks, BITBOARDSET[firstOne]);

				topTempBB = andTwoBitBoards(ATTACKS_TOP[firstOne], board.whitePieces);
				if (!isAllZeroBit(topTempBB))
					topTempBB = BITBOARDSET[findFirstOneInBitBoard(topTempBB)];
			}
			// To get the squares where the cannon can move to, we exclusive OR the board with ATTACKS_TOP[from]
			cannonTopAttacks = xorTwoBitBoards(cannonTopAttacks, ATTACKS_TOP[from]);
			// Eat if possible
			cannonTopAttacks = orTwoBitBoards(cannonTopAttacks, topTempBB);


			// We do this because the first piece will stop the cannon moving to the left.
			cannonLeftAttacks = andTwoBitBoards(ATTACKS_LEFT[from], board.occupiedSquares);
			// Because the first piece will stop the cannon, we need to fill in all the squares to the left of the piece
			if (!isAllZeroBit(cannonLeftAttacks))
			{
				unsigned int lastOne = findLastOneInBitBoard(cannonLeftAttacks);
				cannonLeftAttacks = ATTACKS_LEFT[lastOne];
				cannonLeftAttacks = orTwoBitBoards(cannonLeftAttacks, BITBOARDSET[lastOne]);

				leftTempBB = andTwoBitBoards(ATTACKS_LEFT[lastOne], board.whitePieces);
				if (!isAllZeroBit(leftTempBB))
					leftTempBB = BITBOARDSET[findLastOneInBitBoard(leftTempBB)];
			}
			// To get the squares where the cannon can move to, we exclusive OR the board with ATTACKS_LEFT[from]
			cannonLeftAttacks = xorTwoBitBoards(cannonLeftAttacks, ATTACKS_LEFT[from]);
			// Eat if possible
			cannonLeftAttacks = orTwoBitBoards(cannonLeftAttacks, leftTempBB);


			// We do this because the first piece will stop the cannon moving on the bottom.
			cannonBottomAttacks = andTwoBitBoards(ATTACKS_BOTTOM[from], board.occupiedSquares);
			// Because the first piece will stop the cannon, we need to fill in all the squares on the bottom of the piece
			if (!isAllZeroBit(cannonBottomAttacks))
			{
				unsigned int lastOne = findLastOneInBitBoard(cannonBottomAttacks);
				cannonBottomAttacks = ATTACKS_BOTTOM[lastOne];
				cannonBottomAttacks = orTwoBitBoards(cannonBottomAttacks, BITBOARDSET[lastOne]);

				bottomTempBB = andTwoBitBoards(ATTACKS_BOTTOM[lastOne], board.whitePieces);
				if (!isAllZeroBit(bottomTempBB))
					bottomTempBB = BITBOARDSET[findLastOneInBitBoard(bottomTempBB)];
			}
			// To get the squares where the cannon can move to, we exclusive OR the board with ATTACKS_BOTTOM[from]
			cannonBottomAttacks = xorTwoBitBoards(cannonBottomAttacks, ATTACKS_BOTTOM[from]);
			// Eat if possible
			cannonBottomAttacks = orTwoBitBoards(cannonBottomAttacks, bottomTempBB);

			cannonAttacks = orTwoBitBoards(cannonRightAttacks, cannonTopAttacks);
			cannonAttacks = orTwoBitBoards(cannonAttacks, cannonLeftAttacks);
			cannonAttacks = orTwoBitBoards(cannonAttacks, cannonBottomAttacks);

			tempMove = andTwoBitBoards(cannonAttacks, targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}
	}
	// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	// White to move
	// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	else
	{
		// we cannot capture one of our own pieces!
		targetBitBoard = notBitBoard(board.whitePieces);

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// White horses
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		setPiec(&move, WHITE_HORSE);
		tempPiece = board.whiteHorses;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			clearBitBoard(&tempMove);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, HORSE_OBSTRUCTS[from][0])))
				tempMove = orTwoBitBoards(tempMove, HORSE_ATTACKS[from][0]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, HORSE_OBSTRUCTS[from][1])))
				tempMove = orTwoBitBoards(tempMove, HORSE_ATTACKS[from][1]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, HORSE_OBSTRUCTS[from][2])))
				tempMove = orTwoBitBoards(tempMove, HORSE_ATTACKS[from][2]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, HORSE_OBSTRUCTS[from][3])))
				tempMove = orTwoBitBoards(tempMove, HORSE_ATTACKS[from][3]);

			tempMove = andTwoBitBoards(tempMove, targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// White elephants
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		clear(&move);
		setPiec(&move, WHITE_ELEPHANT);
		tempPiece = board.whiteElephants;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);
			clearBitBoard(&tempMove);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, ELEPHANT_OBSTRUCTS[from][0])))
				tempMove = orTwoBitBoards(tempMove, ELEPHANT_ATTACKS[from][0]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, ELEPHANT_OBSTRUCTS[from][1])))
				tempMove = orTwoBitBoards(tempMove, ELEPHANT_ATTACKS[from][1]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, ELEPHANT_OBSTRUCTS[from][2])))
				tempMove = orTwoBitBoards(tempMove, ELEPHANT_ATTACKS[from][2]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, ELEPHANT_OBSTRUCTS[from][3])))
				tempMove = orTwoBitBoards(tempMove, ELEPHANT_ATTACKS[from][3]);
			tempMove = andTwoBitBoards(tempMove, targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// White advisors
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		clear(&move);
		setPiec(&move, WHITE_ADVISOR);
		tempPiece = board.whiteAdvisors;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			tempMove = andTwoBitBoards(ADVISOR_ATTACKS[from], targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// white king
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		clear(&move);
		setPiec(&move, WHITE_KING);
		tempPiece = board.whiteKing;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			tempMove = andTwoBitBoards(KING_ATTACKS[from], targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// White pawns
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		clear(&move);
		setPiec(&move, WHITE_PAWN);
		tempPiece = board.whitePawns;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			tempMove = andTwoBitBoards(WHITE_PAWN_ATTACKS[from], targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// White rooks
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		BITBOARD rookAttacks, rookRightAttacks, rookTopAttacks, rookLeftAttacks, rookBottomAttacks;
		clear(&move);
		setPiec(&move, WHITE_ROOK);
		tempPiece = board.whiteRooks;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			// We do this because the first piece will stop the rook moving to the right.
			rookRightAttacks = andTwoBitBoards(ATTACKS_RIGHT[from], board.occupiedSquares);
			// Because the first piece will stop the rook, we need to fill in all the squares to the right of the piece
			if (!isAllZeroBit(rookRightAttacks))
				rookRightAttacks = ATTACKS_RIGHT[findFirstOneInBitBoard(rookRightAttacks)];
			// To get the squares where the rook can move to, we exclusive OR the board with ATTACKS_RIGHT[from]
			rookRightAttacks = xorTwoBitBoards(rookRightAttacks, ATTACKS_RIGHT[from]);

			// We do this because the first piece will stop the rook moving on the top.
			rookTopAttacks = andTwoBitBoards(ATTACKS_TOP[from], board.occupiedSquares);
			// Because the first piece will stop the rook, we need to fill in all the squares on the top of the piece
			if (!isAllZeroBit(rookTopAttacks))
				rookTopAttacks = ATTACKS_TOP[findFirstOneInBitBoard(rookTopAttacks)];
			// To get the squares where the rook can move to, we exclusive OR the board with ATTACKS_TOP[from]
			rookTopAttacks = xorTwoBitBoards(rookTopAttacks, ATTACKS_TOP[from]);

			// We do this because the first piece will stop the rook moving to the left.
			rookLeftAttacks = andTwoBitBoards(ATTACKS_LEFT[from], board.occupiedSquares);
			// Because the first piece will stop the rook, we need to fill in all the squares to the left of the piece
			if (!isAllZeroBit(rookLeftAttacks))
				rookLeftAttacks = ATTACKS_LEFT[findLastOneInBitBoard(rookLeftAttacks)];
			// To get the squares where the rook can move to, we exclusive OR the board with ATTACKS_LEFT[from]
			rookLeftAttacks = xorTwoBitBoards(rookLeftAttacks, ATTACKS_LEFT[from]);

			// We do this because the first piece will stop the rook moving on the bottom.
			rookBottomAttacks = andTwoBitBoards(ATTACKS_BOTTOM[from], board.occupiedSquares);
			// Because the first piece will stop the rook, we need to fill in all the squares on the bottom of the piece
			if (!isAllZeroBit(rookBottomAttacks))
				rookBottomAttacks = ATTACKS_BOTTOM[findLastOneInBitBoard(rookBottomAttacks)];
			// To get the squares where the rook can move to, we exclusive OR the board with ATTACKS_BOTTOM[from]
			rookBottomAttacks = xorTwoBitBoards(rookBottomAttacks, ATTACKS_BOTTOM[from]);

			rookAttacks = orTwoBitBoards(rookRightAttacks, rookTopAttacks);
			rookAttacks = orTwoBitBoards(rookAttacks, rookLeftAttacks);
			rookAttacks = orTwoBitBoards(rookAttacks, rookBottomAttacks);

			tempMove = andTwoBitBoards(rookAttacks, targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// White cannons
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		BITBOARD cannonAttacks, cannonRightAttacks, cannonTopAttacks, cannonLeftAttacks, cannonBottomAttacks;
		BITBOARD rightTempBB, topTempBB, leftTempBB, bottomTempBB;
		clear(&move);
		setPiec(&move, WHITE_CANNON);
		tempPiece = board.whiteCannons;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			clearBitBoard(&rightTempBB);
			clearBitBoard(&topTempBB);
			clearBitBoard(&leftTempBB);
			clearBitBoard(&bottomTempBB);

			// We do this because the first piece will stop the rook moving to the right.
			cannonRightAttacks = andTwoBitBoards(ATTACKS_RIGHT[from], board.occupiedSquares);
			// Because the first piece will stop the cannon, we need to fill in all the squares to the right of the piece
			if (!isAllZeroBit(cannonRightAttacks))
			{
				unsigned int firstOne = findFirstOneInBitBoard(cannonRightAttacks);
				cannonRightAttacks = ATTACKS_RIGHT[firstOne];
				cannonRightAttacks = orTwoBitBoards(cannonRightAttacks, BITBOARDSET[firstOne]);

				rightTempBB = andTwoBitBoards(ATTACKS_RIGHT[firstOne], board.blackPieces);
				if (!isAllZeroBit(rightTempBB))
					rightTempBB = BITBOARDSET[findFirstOneInBitBoard(rightTempBB)];
			}
			// To get the squares where the cannon can move to, we exclusive OR the board with ATTACKS_RIGHT[from]
			cannonRightAttacks = xorTwoBitBoards(cannonRightAttacks, ATTACKS_RIGHT[from]);
			// Eat if possible
			cannonRightAttacks = orTwoBitBoards(cannonRightAttacks, rightTempBB);


			// We do this because the first piece will stop the cannon moving on the top.
			cannonTopAttacks = andTwoBitBoards(ATTACKS_TOP[from], board.occupiedSquares);
			// Because the first piece will stop the cannon, we need to fill in all the squares on the top of the piece
			if (!isAllZeroBit(cannonTopAttacks))
			{
				unsigned int firstOne = findFirstOneInBitBoard(cannonTopAttacks);
				cannonTopAttacks = ATTACKS_TOP[firstOne];
				cannonTopAttacks = orTwoBitBoards(cannonTopAttacks, BITBOARDSET[firstOne]);

				topTempBB = andTwoBitBoards(ATTACKS_TOP[firstOne], board.blackPieces);
				if (!isAllZeroBit(topTempBB))
					topTempBB = BITBOARDSET[findFirstOneInBitBoard(topTempBB)];
			}
			// To get the squares where the cannon can move to, we exclusive OR the board with ATTACKS_TOP[from]
			cannonTopAttacks = xorTwoBitBoards(cannonTopAttacks, ATTACKS_TOP[from]);
			// Eat if possible
			cannonTopAttacks = orTwoBitBoards(cannonTopAttacks, topTempBB);


			// We do this because the first piece will stop the cannon moving to the left.
			cannonLeftAttacks = andTwoBitBoards(ATTACKS_LEFT[from], board.occupiedSquares);
			// Because the first piece will stop the cannon, we need to fill in all the squares to the left of the piece
			if (!isAllZeroBit(cannonLeftAttacks))
			{
				unsigned int lastOne = findLastOneInBitBoard(cannonLeftAttacks);
				cannonLeftAttacks = ATTACKS_LEFT[lastOne];
				cannonLeftAttacks = orTwoBitBoards(cannonLeftAttacks, BITBOARDSET[lastOne]);

				leftTempBB = andTwoBitBoards(ATTACKS_LEFT[lastOne], board.blackPieces);
				if (!isAllZeroBit(leftTempBB))
					leftTempBB = BITBOARDSET[findLastOneInBitBoard(leftTempBB)];
			}
			// To get the squares where the cannon can move to, we exclusive OR the board with ATTACKS_LEFT[from]
			cannonLeftAttacks = xorTwoBitBoards(cannonLeftAttacks, ATTACKS_LEFT[from]);
			// Eat if possible
			cannonLeftAttacks = orTwoBitBoards(cannonLeftAttacks, leftTempBB);


			// We do this because the first piece will stop the cannon moving on the bottom.
			cannonBottomAttacks = andTwoBitBoards(ATTACKS_BOTTOM[from], board.occupiedSquares);
			// Because the first piece will stop the cannon, we need to fill in all the squares on the bottom of the piece
			if (!isAllZeroBit(cannonBottomAttacks))
			{
				unsigned int lastOne = findLastOneInBitBoard(cannonBottomAttacks);
				cannonBottomAttacks = ATTACKS_BOTTOM[lastOne];
				cannonBottomAttacks = orTwoBitBoards(cannonBottomAttacks, BITBOARDSET[lastOne]);

				bottomTempBB = andTwoBitBoards(ATTACKS_BOTTOM[lastOne], board.blackPieces);
				if (!isAllZeroBit(bottomTempBB))
					bottomTempBB = BITBOARDSET[findLastOneInBitBoard(bottomTempBB)];
			}
			// To get the squares where the cannon can move to, we exclusive OR the board with ATTACKS_BOTTOM[from]
			cannonBottomAttacks = xorTwoBitBoards(cannonBottomAttacks, ATTACKS_BOTTOM[from]);
			// Eat if possible
			cannonBottomAttacks = orTwoBitBoards(cannonBottomAttacks, bottomTempBB);

			cannonAttacks = orTwoBitBoards(cannonRightAttacks, cannonTopAttacks);
			cannonAttacks = orTwoBitBoards(cannonAttacks, cannonLeftAttacks);
			cannonAttacks = orTwoBitBoards(cannonAttacks, cannonBottomAttacks);

			tempMove = andTwoBitBoards(cannonAttacks, targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}
	}

	return index;
}


unsigned int captgen(unsigned int index)
{
	// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	// This is pseudo-legal bitboard capture generator,
	// using magic multiplication instead of rotated bitboards.
	// There is no check if a capture leaves the king in check
	// The first free location in moveBuffer[] is supplied in index,
	// and the new first free location is returned
	// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

	unsigned int from, to;
	BITBOARD tempPiece, tempMove;
	BITBOARD targetBitBoard;
	MOVE move;

	clear(&move);

	// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	// Black to move
	// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	if (board.nextMove)
	{
		// we want captures only!
		targetBitBoard = board.whitePieces;

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// Black horses
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		setPiec(&move, BLACK_HORSE);
		tempPiece = board.blackHorses;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			clearBitBoard(&tempMove);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, HORSE_OBSTRUCTS[from][0])))
				tempMove = orTwoBitBoards(tempMove, HORSE_ATTACKS[from][0]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, HORSE_OBSTRUCTS[from][1])))
				tempMove = orTwoBitBoards(tempMove, HORSE_ATTACKS[from][1]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, HORSE_OBSTRUCTS[from][2])))
				tempMove = orTwoBitBoards(tempMove, HORSE_ATTACKS[from][2]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, HORSE_OBSTRUCTS[from][3])))
				tempMove = orTwoBitBoards(tempMove, HORSE_ATTACKS[from][3]);

			tempMove = andTwoBitBoards(tempMove, targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// Black elephants
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		clear(&move);
		setPiec(&move, BLACK_ELEPHANT);
		tempPiece = board.blackElephants;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);
			clearBitBoard(&tempMove);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, ELEPHANT_OBSTRUCTS[from][0])))
				tempMove = orTwoBitBoards(tempMove, ELEPHANT_ATTACKS[from][0]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, ELEPHANT_OBSTRUCTS[from][1])))
				tempMove = orTwoBitBoards(tempMove, ELEPHANT_ATTACKS[from][1]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, ELEPHANT_OBSTRUCTS[from][2])))
				tempMove = orTwoBitBoards(tempMove, ELEPHANT_ATTACKS[from][2]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, ELEPHANT_OBSTRUCTS[from][3])))
				tempMove = orTwoBitBoards(tempMove, ELEPHANT_ATTACKS[from][3]);
			tempMove = andTwoBitBoards(tempMove, targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// Black advisors
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		clear(&move);
		setPiec(&move, BLACK_ADVISOR);
		tempPiece = board.blackAdvisors;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			tempMove = andTwoBitBoards(ADVISOR_ATTACKS[from], targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// Black king
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		clear(&move);
		setPiec(&move, BLACK_KING);
		tempPiece = board.blackKing;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			tempMove = andTwoBitBoards(KING_ATTACKS[from], targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// Black pawns
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		clear(&move);
		setPiec(&move, BLACK_PAWN);
		tempPiece = board.blackPawns;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			tempMove = andTwoBitBoards(BLACK_PAWN_ATTACKS[from], targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// Black rooks
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		BITBOARD rookAttacks, rookRightAttacks, rookTopAttacks, rookLeftAttacks, rookBottomAttacks;
		clear(&move);
		setPiec(&move, BLACK_ROOK);
		tempPiece = board.blackRooks;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			// We do this because the first piece will stop the rook moving to the right.
			rookRightAttacks = andTwoBitBoards(ATTACKS_RIGHT[from], board.occupiedSquares);
			// Because the first piece will stop the rook, we need to fill in all the squares to the right of the piece
			if (!isAllZeroBit(rookRightAttacks))
				rookRightAttacks = ATTACKS_RIGHT[findFirstOneInBitBoard(rookRightAttacks)];
			// To get the squares where the rook can move to, we exclusive OR the board with ATTACKS_RIGHT[from]
			rookRightAttacks = xorTwoBitBoards(rookRightAttacks, ATTACKS_RIGHT[from]);

			// We do this because the first piece will stop the rook moving on the top.
			rookTopAttacks = andTwoBitBoards(ATTACKS_TOP[from], board.occupiedSquares);
			// Because the first piece will stop the rook, we need to fill in all the squares on the top of the piece
			if (!isAllZeroBit(rookTopAttacks))
				rookTopAttacks = ATTACKS_TOP[findFirstOneInBitBoard(rookTopAttacks)];
			// To get the squares where the rook can move to, we exclusive OR the board with ATTACKS_TOP[from]
			rookTopAttacks = xorTwoBitBoards(rookTopAttacks, ATTACKS_TOP[from]);

			// We do this because the first piece will stop the rook moving to the left.
			rookLeftAttacks = andTwoBitBoards(ATTACKS_LEFT[from], board.occupiedSquares);
			// Because the first piece will stop the rook, we need to fill in all the squares to the left of the piece
			if (!isAllZeroBit(rookLeftAttacks))
				rookLeftAttacks = ATTACKS_LEFT[findLastOneInBitBoard(rookLeftAttacks)];
			// To get the squares where the rook can move to, we exclusive OR the board with ATTACKS_LEFT[from]
			rookLeftAttacks = xorTwoBitBoards(rookLeftAttacks, ATTACKS_LEFT[from]);

			// We do this because the first piece will stop the rook moving on the bottom.
			rookBottomAttacks = andTwoBitBoards(ATTACKS_BOTTOM[from], board.occupiedSquares);
			// Because the first piece will stop the rook, we need to fill in all the squares on the bottom of the piece
			if (!isAllZeroBit(rookBottomAttacks))
				rookBottomAttacks = ATTACKS_BOTTOM[findLastOneInBitBoard(rookBottomAttacks)];
			// To get the squares where the rook can move to, we exclusive OR the board with ATTACKS_BOTTOM[from]
			rookBottomAttacks = xorTwoBitBoards(rookBottomAttacks, ATTACKS_BOTTOM[from]);

			rookAttacks = orTwoBitBoards(rookRightAttacks, rookTopAttacks);
			rookAttacks = orTwoBitBoards(rookAttacks, rookLeftAttacks);
			rookAttacks = orTwoBitBoards(rookAttacks, rookBottomAttacks);

			tempMove = andTwoBitBoards(rookAttacks, targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// Black cannons
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		BITBOARD cannonAttacks, cannonRightAttacks, cannonTopAttacks, cannonLeftAttacks, cannonBottomAttacks;
		BITBOARD rightTempBB, topTempBB, leftTempBB, bottomTempBB;
		clear(&move);
		setPiec(&move, BLACK_CANNON);
		tempPiece = board.blackCannons;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			clearBitBoard(&rightTempBB);
			clearBitBoard(&topTempBB);
			clearBitBoard(&leftTempBB);
			clearBitBoard(&bottomTempBB);

			// We do this because the first piece will stop the rook moving to the right.
			cannonRightAttacks = andTwoBitBoards(ATTACKS_RIGHT[from], board.occupiedSquares);
			// Because the first piece will stop the cannon, we need to fill in all the squares to the right of the piece
			if (!isAllZeroBit(cannonRightAttacks))
			{
				unsigned int firstOne = findFirstOneInBitBoard(cannonRightAttacks);
				cannonRightAttacks = ATTACKS_RIGHT[firstOne];
				cannonRightAttacks = orTwoBitBoards(cannonRightAttacks, BITBOARDSET[firstOne]);

				rightTempBB = andTwoBitBoards(ATTACKS_RIGHT[firstOne], board.whitePieces);
				if (!isAllZeroBit(rightTempBB))
					rightTempBB = BITBOARDSET[findFirstOneInBitBoard(rightTempBB)];
			}
			// To get the squares where the cannon can move to, we exclusive OR the board with ATTACKS_RIGHT[from]
			cannonRightAttacks = xorTwoBitBoards(cannonRightAttacks, ATTACKS_RIGHT[from]);
			// Eat if possible
			cannonRightAttacks = orTwoBitBoards(cannonRightAttacks, rightTempBB);


			// We do this because the first piece will stop the cannon moving on the top.
			cannonTopAttacks = andTwoBitBoards(ATTACKS_TOP[from], board.occupiedSquares);
			// Because the first piece will stop the cannon, we need to fill in all the squares on the top of the piece
			if (!isAllZeroBit(cannonTopAttacks))
			{
				unsigned int firstOne = findFirstOneInBitBoard(cannonTopAttacks);
				cannonTopAttacks = ATTACKS_TOP[firstOne];
				cannonTopAttacks = orTwoBitBoards(cannonTopAttacks, BITBOARDSET[firstOne]);

				topTempBB = andTwoBitBoards(ATTACKS_TOP[firstOne], board.whitePieces);
				if (!isAllZeroBit(topTempBB))
					topTempBB = BITBOARDSET[findFirstOneInBitBoard(topTempBB)];
			}
			// To get the squares where the cannon can move to, we exclusive OR the board with ATTACKS_TOP[from]
			cannonTopAttacks = xorTwoBitBoards(cannonTopAttacks, ATTACKS_TOP[from]);
			// Eat if possible
			cannonTopAttacks = orTwoBitBoards(cannonTopAttacks, topTempBB);


			// We do this because the first piece will stop the cannon moving to the left.
			cannonLeftAttacks = andTwoBitBoards(ATTACKS_LEFT[from], board.occupiedSquares);
			// Because the first piece will stop the cannon, we need to fill in all the squares to the left of the piece
			if (!isAllZeroBit(cannonLeftAttacks))
			{
				unsigned int lastOne = findLastOneInBitBoard(cannonLeftAttacks);
				cannonLeftAttacks = ATTACKS_LEFT[lastOne];
				cannonLeftAttacks = orTwoBitBoards(cannonLeftAttacks, BITBOARDSET[lastOne]);

				leftTempBB = andTwoBitBoards(ATTACKS_LEFT[lastOne], board.whitePieces);
				if (!isAllZeroBit(leftTempBB))
					leftTempBB = BITBOARDSET[findLastOneInBitBoard(leftTempBB)];
			}
			// To get the squares where the cannon can move to, we exclusive OR the board with ATTACKS_LEFT[from]
			cannonLeftAttacks = xorTwoBitBoards(cannonLeftAttacks, ATTACKS_LEFT[from]);
			// Eat if possible
			cannonLeftAttacks = orTwoBitBoards(cannonLeftAttacks, leftTempBB);


			// We do this because the first piece will stop the cannon moving on the bottom.
			cannonBottomAttacks = andTwoBitBoards(ATTACKS_BOTTOM[from], board.occupiedSquares);
			// Because the first piece will stop the cannon, we need to fill in all the squares on the bottom of the piece
			if (!isAllZeroBit(cannonBottomAttacks))
			{
				unsigned int lastOne = findLastOneInBitBoard(cannonBottomAttacks);
				cannonBottomAttacks = ATTACKS_BOTTOM[lastOne];
				cannonBottomAttacks = orTwoBitBoards(cannonBottomAttacks, BITBOARDSET[lastOne]);

				bottomTempBB = andTwoBitBoards(ATTACKS_BOTTOM[lastOne], board.whitePieces);
				if (!isAllZeroBit(bottomTempBB))
					bottomTempBB = BITBOARDSET[findLastOneInBitBoard(bottomTempBB)];
			}
			// To get the squares where the cannon can move to, we exclusive OR the board with ATTACKS_BOTTOM[from]
			cannonBottomAttacks = xorTwoBitBoards(cannonBottomAttacks, ATTACKS_BOTTOM[from]);
			// Eat if possible
			cannonBottomAttacks = orTwoBitBoards(cannonBottomAttacks, bottomTempBB);

			cannonAttacks = orTwoBitBoards(cannonRightAttacks, cannonTopAttacks);
			cannonAttacks = orTwoBitBoards(cannonAttacks, cannonLeftAttacks);
			cannonAttacks = orTwoBitBoards(cannonAttacks, cannonBottomAttacks);

			tempMove = andTwoBitBoards(cannonAttacks, targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}
	}
	// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	// White to move
	// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	else
	{
		// we want captures only!
		targetBitBoard = board.blackPieces;

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// White horses
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		setPiec(&move, WHITE_HORSE);
		tempPiece = board.whiteHorses;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			clearBitBoard(&tempMove);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, HORSE_OBSTRUCTS[from][0])))
				tempMove = orTwoBitBoards(tempMove, HORSE_ATTACKS[from][0]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, HORSE_OBSTRUCTS[from][1])))
				tempMove = orTwoBitBoards(tempMove, HORSE_ATTACKS[from][1]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, HORSE_OBSTRUCTS[from][2])))
				tempMove = orTwoBitBoards(tempMove, HORSE_ATTACKS[from][2]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, HORSE_OBSTRUCTS[from][3])))
				tempMove = orTwoBitBoards(tempMove, HORSE_ATTACKS[from][3]);

			tempMove = andTwoBitBoards(tempMove, targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// White elephants
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		clear(&move);
		setPiec(&move, WHITE_ELEPHANT);
		tempPiece = board.whiteElephants;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);
			clearBitBoard(&tempMove);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, ELEPHANT_OBSTRUCTS[from][0])))
				tempMove = orTwoBitBoards(tempMove, ELEPHANT_ATTACKS[from][0]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, ELEPHANT_OBSTRUCTS[from][1])))
				tempMove = orTwoBitBoards(tempMove, ELEPHANT_ATTACKS[from][1]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, ELEPHANT_OBSTRUCTS[from][2])))
				tempMove = orTwoBitBoards(tempMove, ELEPHANT_ATTACKS[from][2]);
			if (isAllZeroBit(andTwoBitBoards(board.occupiedSquares, ELEPHANT_OBSTRUCTS[from][3])))
				tempMove = orTwoBitBoards(tempMove, ELEPHANT_ATTACKS[from][3]);
			tempMove = andTwoBitBoards(tempMove, targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// White advisors
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		clear(&move);
		setPiec(&move, WHITE_ADVISOR);
		tempPiece = board.whiteAdvisors;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			tempMove = andTwoBitBoards(ADVISOR_ATTACKS[from], targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// white king
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		clear(&move);
		setPiec(&move, WHITE_KING);
		tempPiece = board.whiteKing;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			tempMove = andTwoBitBoards(KING_ATTACKS[from], targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// White pawns
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		clear(&move);
		setPiec(&move, WHITE_PAWN);
		tempPiece = board.whitePawns;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			tempMove = andTwoBitBoards(WHITE_PAWN_ATTACKS[from], targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// White rooks
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		BITBOARD rookAttacks, rookRightAttacks, rookTopAttacks, rookLeftAttacks, rookBottomAttacks;
		clear(&move);
		setPiec(&move, WHITE_ROOK);
		tempPiece = board.whiteRooks;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			// We do this because the first piece will stop the rook moving to the right.
			rookRightAttacks = andTwoBitBoards(ATTACKS_RIGHT[from], board.occupiedSquares);
			// Because the first piece will stop the rook, we need to fill in all the squares to the right of the piece
			if (!isAllZeroBit(rookRightAttacks))
				rookRightAttacks = ATTACKS_RIGHT[findFirstOneInBitBoard(rookRightAttacks)];
			// To get the squares where the rook can move to, we exclusive OR the board with ATTACKS_RIGHT[from]
			rookRightAttacks = xorTwoBitBoards(rookRightAttacks, ATTACKS_RIGHT[from]);

			// We do this because the first piece will stop the rook moving on the top.
			rookTopAttacks = andTwoBitBoards(ATTACKS_TOP[from], board.occupiedSquares);
			// Because the first piece will stop the rook, we need to fill in all the squares on the top of the piece
			if (!isAllZeroBit(rookTopAttacks))
				rookTopAttacks = ATTACKS_TOP[findFirstOneInBitBoard(rookTopAttacks)];
			// To get the squares where the rook can move to, we exclusive OR the board with ATTACKS_TOP[from]
			rookTopAttacks = xorTwoBitBoards(rookTopAttacks, ATTACKS_TOP[from]);

			// We do this because the first piece will stop the rook moving to the left.
			rookLeftAttacks = andTwoBitBoards(ATTACKS_LEFT[from], board.occupiedSquares);
			// Because the first piece will stop the rook, we need to fill in all the squares to the left of the piece
			if (!isAllZeroBit(rookLeftAttacks))
				rookLeftAttacks = ATTACKS_LEFT[findLastOneInBitBoard(rookLeftAttacks)];
			// To get the squares where the rook can move to, we exclusive OR the board with ATTACKS_LEFT[from]
			rookLeftAttacks = xorTwoBitBoards(rookLeftAttacks, ATTACKS_LEFT[from]);

			// We do this because the first piece will stop the rook moving on the bottom.
			rookBottomAttacks = andTwoBitBoards(ATTACKS_BOTTOM[from], board.occupiedSquares);
			// Because the first piece will stop the rook, we need to fill in all the squares on the bottom of the piece
			if (!isAllZeroBit(rookBottomAttacks))
				rookBottomAttacks = ATTACKS_BOTTOM[findLastOneInBitBoard(rookBottomAttacks)];
			// To get the squares where the rook can move to, we exclusive OR the board with ATTACKS_BOTTOM[from]
			rookBottomAttacks = xorTwoBitBoards(rookBottomAttacks, ATTACKS_BOTTOM[from]);

			rookAttacks = orTwoBitBoards(rookRightAttacks, rookTopAttacks);
			rookAttacks = orTwoBitBoards(rookAttacks, rookLeftAttacks);
			rookAttacks = orTwoBitBoards(rookAttacks, rookBottomAttacks);

			tempMove = andTwoBitBoards(rookAttacks, targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}

		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		// White cannons
		// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
		BITBOARD cannonAttacks, cannonRightAttacks, cannonTopAttacks, cannonLeftAttacks, cannonBottomAttacks;
		BITBOARD rightTempBB, topTempBB, leftTempBB, bottomTempBB;
		clear(&move);
		setPiec(&move, WHITE_CANNON);
		tempPiece = board.whiteCannons;
		while (!isAllZeroBit(tempPiece))
		{
			from = findFirstOneInBitBoard(tempPiece);
			setFrom(&move, from);

			clearBitBoard(&rightTempBB);
			clearBitBoard(&topTempBB);
			clearBitBoard(&leftTempBB);
			clearBitBoard(&bottomTempBB);

			// We do this because the first piece will stop the rook moving to the right.
			cannonRightAttacks = andTwoBitBoards(ATTACKS_RIGHT[from], board.occupiedSquares);
			// Because the first piece will stop the cannon, we need to fill in all the squares to the right of the piece
			if (!isAllZeroBit(cannonRightAttacks))
			{
				unsigned int firstOne = findFirstOneInBitBoard(cannonRightAttacks);
				cannonRightAttacks = ATTACKS_RIGHT[firstOne];
				cannonRightAttacks = orTwoBitBoards(cannonRightAttacks, BITBOARDSET[firstOne]);

				rightTempBB = andTwoBitBoards(ATTACKS_RIGHT[firstOne], board.blackPieces);
				if (!isAllZeroBit(rightTempBB))
					rightTempBB = BITBOARDSET[findFirstOneInBitBoard(rightTempBB)];
			}
			// To get the squares where the cannon can move to, we exclusive OR the board with ATTACKS_RIGHT[from]
			cannonRightAttacks = xorTwoBitBoards(cannonRightAttacks, ATTACKS_RIGHT[from]);
			// Eat if possible
			cannonRightAttacks = orTwoBitBoards(cannonRightAttacks, rightTempBB);


			// We do this because the first piece will stop the cannon moving on the top.
			cannonTopAttacks = andTwoBitBoards(ATTACKS_TOP[from], board.occupiedSquares);
			// Because the first piece will stop the cannon, we need to fill in all the squares on the top of the piece
			if (!isAllZeroBit(cannonTopAttacks))
			{
				unsigned int firstOne = findFirstOneInBitBoard(cannonTopAttacks);
				cannonTopAttacks = ATTACKS_TOP[firstOne];
				cannonTopAttacks = orTwoBitBoards(cannonTopAttacks, BITBOARDSET[firstOne]);

				topTempBB = andTwoBitBoards(ATTACKS_TOP[firstOne], board.blackPieces);
				if (!isAllZeroBit(topTempBB))
					topTempBB = BITBOARDSET[findFirstOneInBitBoard(topTempBB)];
			}
			// To get the squares where the cannon can move to, we exclusive OR the board with ATTACKS_TOP[from]
			cannonTopAttacks = xorTwoBitBoards(cannonTopAttacks, ATTACKS_TOP[from]);
			// Eat if possible
			cannonTopAttacks = orTwoBitBoards(cannonTopAttacks, topTempBB);


			// We do this because the first piece will stop the cannon moving to the left.
			cannonLeftAttacks = andTwoBitBoards(ATTACKS_LEFT[from], board.occupiedSquares);
			// Because the first piece will stop the cannon, we need to fill in all the squares to the left of the piece
			if (!isAllZeroBit(cannonLeftAttacks))
			{
				unsigned int lastOne = findLastOneInBitBoard(cannonLeftAttacks);
				cannonLeftAttacks = ATTACKS_LEFT[lastOne];
				cannonLeftAttacks = orTwoBitBoards(cannonLeftAttacks, BITBOARDSET[lastOne]);

				leftTempBB = andTwoBitBoards(ATTACKS_LEFT[lastOne], board.blackPieces);
				if (!isAllZeroBit(leftTempBB))
					leftTempBB = BITBOARDSET[findLastOneInBitBoard(leftTempBB)];
			}
			// To get the squares where the cannon can move to, we exclusive OR the board with ATTACKS_LEFT[from]
			cannonLeftAttacks = xorTwoBitBoards(cannonLeftAttacks, ATTACKS_LEFT[from]);
			// Eat if possible
			cannonLeftAttacks = orTwoBitBoards(cannonLeftAttacks, leftTempBB);


			// We do this because the first piece will stop the cannon moving on the bottom.
			cannonBottomAttacks = andTwoBitBoards(ATTACKS_BOTTOM[from], board.occupiedSquares);
			// Because the first piece will stop the cannon, we need to fill in all the squares on the bottom of the piece
			if (!isAllZeroBit(cannonBottomAttacks))
			{
				unsigned int lastOne = findLastOneInBitBoard(cannonBottomAttacks);
				cannonBottomAttacks = ATTACKS_BOTTOM[lastOne];
				cannonBottomAttacks = orTwoBitBoards(cannonBottomAttacks, BITBOARDSET[lastOne]);

				bottomTempBB = andTwoBitBoards(ATTACKS_BOTTOM[lastOne], board.blackPieces);
				if (!isAllZeroBit(bottomTempBB))
					bottomTempBB = BITBOARDSET[findLastOneInBitBoard(bottomTempBB)];
			}
			// To get the squares where the cannon can move to, we exclusive OR the board with ATTACKS_BOTTOM[from]
			cannonBottomAttacks = xorTwoBitBoards(cannonBottomAttacks, ATTACKS_BOTTOM[from]);
			// Eat if possible
			cannonBottomAttacks = orTwoBitBoards(cannonBottomAttacks, bottomTempBB);

			cannonAttacks = orTwoBitBoards(cannonRightAttacks, cannonTopAttacks);
			cannonAttacks = orTwoBitBoards(cannonAttacks, cannonLeftAttacks);
			cannonAttacks = orTwoBitBoards(cannonAttacks, cannonBottomAttacks);

			tempMove = andTwoBitBoards(cannonAttacks, targetBitBoard);
			while (!isAllZeroBit(tempMove))
			{
				to = findFirstOneInBitBoard(tempMove);
				setTosq(&move, to);
				setCapt(&move, board.square[to]);
				board.moveBuffer[index++].moveInt = move.moveInt;
				tempMove = xorTwoBitBoards(tempMove, BITBOARDSET[to]);
			}
			tempPiece = xorTwoBitBoards(tempPiece, BITBOARDSET[from]);
		}
	}

	return index;
}


U64 perft(int ply, int depth)
{

	// Raw node count, up to depth, doing a full tree search.
	// perft is very similar to the search algorithm - instead of evaluating the leaves, we count them.
	//
	// Be carefull when calling this function with depths > 7, because it can take a very long
	// time before the result is returned: the average branching factor in chess is 35, so every
	// increment in depth will require 35x more computer time.
	//
	// perft is a good way of verifying correctness of the movegenerator and (un)makeMove,
	// because you can compare the results with published results for certain test positions.
	//
	// perft is also used to measure the performance of the move generator and (un)makeMove in terms
	// of speed, and to compare different implementations of generating, storing and (un)making moves.

	U64 retVal = 0;
	int i;

	// count this node
	if (depth == 0)
	{
		return 1;
	}

	// generate moves from this position
	board.moveBufLen[ply+1] = movegen(board.moveBufLen[ply]);

	// loop over moves:
	for (i = board.moveBufLen[ply]; i < board.moveBufLen[ply+1]; i++)
	{
		makeMove(board.moveBuffer[i]);
		{
			if (!isTwoKingsFaceToFace() && !isOtherKingAttacked())
			{
				// recursively call perft
				retVal += perft(ply + 1, depth-1);
			}
		}
		unMakeMove(board.moveBuffer[i]);
	}

	return retVal;
}



MOVE think()
{
	// This is the entry point for search

	int score, legalmoves, currentdepth;
	MOVE singlemove;

	//	===========================================================================
	//	Check if the game has ended, or if there is only one legal move,
	//  because then we don't need to search:
	//	===========================================================================
	if (isEndOfgame(&legalmoves, &singlemove))
		return NOMOVE;

	if (legalmoves == 1)
	{
		printf("forced move: ");
		displayMove(singlemove);
		printf("\n");

		return singlemove;
	}

	//	===========================================================================
	//	There is more than legal 1 move, so prepare to search:
	//	===========================================================================
	board.lastPVLength = 0;
	memset(board.lastPV, 0 , sizeof(board.lastPV));
	memset(board.whiteHeuristics, 0, sizeof(board.whiteHeuristics));
	memset(board.blackHeuristics, 0, sizeof(board.blackHeuristics));
	board.inodes = 0;

	board.countdown = UPDATEINTERVAL;
	board.timedout = FALSE;

	// display console header
	displaySearchStats(1, 0, 0);
	initTimer(&board.timer);
	board.msStart = getMSTimer(&board.timer);

	//  iterative deepening:
	for (currentdepth = 1; currentdepth <= board.searchDepth; currentdepth++)
	{
		//  clear the buffers:
		memset(board.moveBufLen, 0, sizeof(board.moveBufLen));
		memset(board.moveBuffer, 0, sizeof(board.moveBuffer));
		memset(board.triangularLength, 0, sizeof(board.triangularLength));
		memset(board.triangularArray, 0, sizeof(board.triangularArray));
		board.followpv = TRUE;
		score = alphabetapvs(0, currentdepth, -LARGE_NUMBER, LARGE_NUMBER);

		// now check if time is up
		// if not decide if it makes sense to start another iteration:
		if (board.timedout)
		{
			printf("\n");
			return (board.lastPV[0]);
		}
		else
		{
			board.msStop = getMSTimer(&board.timer);
			if ((board.msStop - board.msStart) > (STOPFRAC * board.maxTime))
			{
				printf("    ok\n");
				return (board.lastPV[0]);
			}
		}

		board.msStop = getMSTimer(&board.timer);
		displaySearchStats(2, currentdepth, score);
		// stop searching if the current depth leads to a forced mate:
		if ((score > (CHECKMATESCORE-currentdepth)) || (score < -(CHECKMATESCORE-currentdepth)))
			currentdepth = board.searchDepth;
	}

	return (board.lastPV[0]);
}

int minimax(int ply, int depth)
{
	// Negamax

	int i, j, val, best;
	best = -LARGE_NUMBER;

	if (depth == 0) return eval();
	board.moveBufLen[ply + 1] = movegen(board.moveBufLen[ply]);
	for (i = board.moveBufLen[ply]; i < board.moveBufLen[ply + 1]; i++)
	{
		makeMove(board.moveBuffer[i]);
		{
			if (isTwoKingsFaceToFace() || isOtherKingAttacked())
				unMakeMove(board.moveBuffer[i]);
			else
			{
				board.inodes++;
				if (!ply)
					displaySearchStats(3, ply, i);

				val = -minimax(ply + 1, depth - 1); // note the minus sign
				unMakeMove(board.moveBuffer[i]);
				if (val > best) // both sides want to maximize from *their* perspective
				{
					best = val;
					board.triangularArray[ply][ply] = board.moveBuffer[i];					// save this move
					for (j = ply + 1; j < board.triangularLength[ply + 1]; j++)
					{
						board.triangularArray[ply][j] = board.triangularArray[ply + 1][j];	// and append the latest best PV from deeper plies
					}
					board.triangularLength[ply] = board.triangularLength[ply + 1];
					if (!ply)
					{
						board.msStop = getMSTimer(&board.timer);
						displaySearchStats(2, depth, val);
					}
				}
			}
		}
	}

	return best;
}

int alphabeta(int ply, int depth, int alpha, int beta)
{
	// Negascout

	int i, j, val;
	board.triangularLength[ply] = ply;

	if (depth == 0)
		return eval();

	board.moveBufLen[ply+1] = movegen(board.moveBufLen[ply]);

	for (i = board.moveBufLen[ply]; i < board.moveBufLen[ply+1]; i++)
	{
		makeMove(board.moveBuffer[i]);
		{
			if (isTwoKingsFaceToFace() || isOtherKingAttacked())
				unMakeMove(board.moveBuffer[i]);
			else
			{
				board.inodes++;
				if (!ply)
					displaySearchStats(3, ply, i);

				val = -alphabeta(ply+1, depth-1, -beta, -alpha);
				unMakeMove(board.moveBuffer[i]);
				if (val >= beta)
				{
					return beta;
				}
				if (val > alpha)
				{
					alpha = val;												// both sides want to maximize from *their* perspective
					board.triangularArray[ply][ply] = board.moveBuffer[i];					// save this move
					for (j = ply + 1; j < board.triangularLength[ply + 1]; j++)
					{
						board.triangularArray[ply][j] = board.triangularArray[ply+1][j];	// and append the latest best PV from deeper plies
					}
					board.triangularLength[ply] = board.triangularLength[ply + 1];
					if (!ply)
					{
						board.msStop = getMSTimer(&board.timer);
						displaySearchStats(2, depth, val);
					}
				}
			}
		}
	}

	return alpha;
}

int alphabetapvs(int ply, int depth, int alpha, int beta)
{
	// PV search

	int i, j, movesfound, pvmovesfound, val;
	board.triangularLength[ply] = ply;

	if (depth == 0)
	{
		board.followpv = FALSE;
		// go into the quiescence search:
		return qsearch(ply, alpha, beta);
	}

	movesfound = 0;
	pvmovesfound = 0;
	board.moveBufLen[ply+1] = movegen(board.moveBufLen[ply]);
	for (i = board.moveBufLen[ply]; i < board.moveBufLen[ply+1]; i++)
	{
		selectmove(ply, i, depth, board.followpv);
		makeMove(board.moveBuffer[i]);
		{
			if (isTwoKingsFaceToFace() || isOtherKingAttacked())
				unMakeMove(board.moveBuffer[i]);
			else
			{
				board.inodes++;

				if (--board.countdown <= 0)
					readClockAndInput();

				movesfound++;
				if (!ply)
					displaySearchStats(3, ply, i);

				if (pvmovesfound)
				{
					val = -alphabetapvs(ply+1, depth-1, -alpha-1, -alpha);
					if ((val > alpha) && (val < beta))
					{
						val = -alphabetapvs(ply+1, depth - 1, -beta, -alpha);   // In case of failure, proceed with normal alphabeta
					}
				}
				else val = -alphabetapvs(ply+1, depth-1, -beta, -alpha);	    // Normal alphabeta
				unMakeMove(board.moveBuffer[i]);

				if (board.timedout)
					return 0;

				if (val >= beta)
				{
					// update the history heuristic
					if (board.nextMove)
						board.blackHeuristics[getFrom(board.moveBuffer[i])][getTosq(board.moveBuffer[i])] += depth*depth;
					else
						board.whiteHeuristics[getFrom(board.moveBuffer[i])][getTosq(board.moveBuffer[i])] += depth*depth;

					return beta;
				}

				if (val > alpha)
				{
					alpha = val;								    // both sides want to maximize from *their* perspective
					pvmovesfound++;
					board.triangularArray[ply][ply] = board.moveBuffer[i];					// save this move
					for (j = ply + 1; j < board.triangularLength[ply+1]; j++)
					{
						board.triangularArray[ply][j] = board.triangularArray[ply+1][j];	// and append the latest best PV from deeper plies
					}
					board.triangularLength[ply] = board.triangularLength[ply+1];
					if (!ply)
					{
						board.msStop = getMSTimer(&board.timer);
						displaySearchStats(2, depth, val);
					}
				}
			}
		}
	}

	// update the history heuristic
	if (pvmovesfound)
	{
		if (board.nextMove)
			board.blackHeuristics[getFrom(board.triangularArray[ply][ply])][getTosq(board.triangularArray[ply][ply])] += depth*depth;
		else
			board.whiteHeuristics[getFrom(board.triangularArray[ply][ply])][getTosq(board.triangularArray[ply][ply])] += depth*depth;
	}

	//	===========================================================================
	//	Checkmate/stalemate detection:
	//	===========================================================================
	if (!movesfound)
		return (-CHECKMATESCORE+ply-1);

	return alpha;
}

void displaySearchStats(int mode, int depth, int score)
{
	// displays various search statistics
	// only to be used when ply = 0
	// mode = 1 : display header
	// mode = 2 : display full stats, including score and latest PV
	// mode = 3 : display current root move that is being searched
	//			  depth = ply, score = loop counter in the search move list

	int i;
	U64 dt;
	char timestring[80];

	dt = getMSTimer(&board.timer) - board.msStart;
	switch (mode)
	{
	case 1:
		printf("depth  score   nodes     time  knps PV\n");
		break;

	case 2:
		// depth
		printf("%5d ", depth);

		// score
		printf("%+6.2f ", score/100.0);

		// nodes searched
		if      (board.inodes > 100000000)
			printf("%6.0f%c ", board.inodes/1000000.0, 'M');
		else if (board.inodes > 10000000)
			printf("%6.2f%c ", board.inodes/1000000.0, 'M');
		else if (board.inodes > 1000000)
			printf("%6.0f%c ", board.inodes/1000.0,    'K');
		else if (board.inodes > 100000)
			printf("%6.1f%c ", board.inodes/1000.0,    'K');
		else if (board.inodes > 10000)
			printf("%6.2f%c ", board.inodes/1000.0,    'K');
		else
			printf("%7"PRINTF_INT64_MODIFIER"u ", board.inodes);

		// search time
		mstostring(dt, timestring);
		printf("%8s ", timestring);

		// search speed
		if (dt > 0)
			printf("%5"PRINTF_INT64_MODIFIER"u ", board.inodes/dt);
		else
			printf("    - ");

		// store this PV:
		rememberPV();

		// PV
		for (i = 0; i < board.triangularLength[0]; i++)
		{
			displayMove(board.triangularArray[0][i]);
			printf(" ");
		}
		printf("\n");
		break;

	case 3:
		if (!TOCONSOLE) break;

		mstostring(dt, timestring);
		printf("             (%2d/%2d) %8s       ", score+1, board.moveBufLen[depth+1]-board.moveBufLen[depth], timestring);

		unMakeMove(board.moveBuffer[score]);

		displayMove(board.moveBuffer[score]);

		makeMove(board.moveBuffer[score]);

		printf("...    \r");
		fflush(stdout);
		break;

	default: break;
	}

	return;
}

BOOL isEndOfgame(int *legalmoves, MOVE *singlemove)
{
	// Checks if the current position is end-of-game due to:
	// checkmate, stalemate


	// are we checkmating the other side?
	if (isTwoKingsFaceToFace() || isOtherKingAttacked())
	{
		if (board.nextMove)
			printf("1-0 {White wins}\n");
		else
			printf("0-1 {Black wins}\n");

		return TRUE;
	}

	// how many legal moves do we have?
	int i;
	(*legalmoves) = 0;
	board.moveBufLen[0] = 0;
	board.moveBufLen[1] = movegen(board.moveBufLen[0]);
	for (i = board.moveBufLen[0]; i < board.moveBufLen[1]; i++)
	{
		makeMove(board.moveBuffer[i]);
		if (!isTwoKingsFaceToFace() && !isOtherKingAttacked())
		{
			(*legalmoves)++;
			singlemove->moveInt = board.moveBuffer[i].moveInt;
		}
		unMakeMove(board.moveBuffer[i]);
	}

	// checkmate or stalemate?
	if (!(*legalmoves))
	{
		if (board.nextMove)
			printf("1-0 {White wins}\n");
		else
			printf("0-1 {Black wins}\n");

		return TRUE;
	}

	return FALSE;
}

void rememberPV()
{
	// remember the last PV
	int i;
	board.lastPVLength = board.triangularLength[0];
	for (i = 0; i < board.triangularLength[0]; i++)
	{
		board.lastPV[i] = board.triangularArray[0][i];
	}
}


void selectmove(int ply, int i, int depth, BOOL followpv)
{
	int j, k;
	unsigned int best;
	MOVE temp;

	// re-orders the move list so that the best move is selected as the next move to try.
	if (followpv && depth > 1)
	{
		for (j = i + 1; j < board.moveBufLen[ply+1]; j++)
		{
			if (board.moveBuffer[j].moveInt == board.lastPV[ply].moveInt)
			{
				temp.moveInt = board.moveBuffer[j].moveInt;
				board.moveBuffer[j].moveInt = board.moveBuffer[i].moveInt;
				board.moveBuffer[i].moveInt = temp.moveInt;
				return;
			}
		}
	}

	if (board.nextMove)
	{
		best = board.blackHeuristics[getFrom(board.moveBuffer[i])][getTosq(board.moveBuffer[i])];
		j = i;
		for (k = i + 1; k < board.moveBufLen[ply+1]; k++)
		{
			if (board.blackHeuristics[getFrom(board.moveBuffer[k])][getTosq(board.moveBuffer[k])] > best)
			{
				best = board.blackHeuristics[getFrom(board.moveBuffer[k])][getTosq(board.moveBuffer[k])];
				j = k;
			}
		}
		if (j > i)
		{
			temp.moveInt = board.moveBuffer[j].moveInt;
			board.moveBuffer[j].moveInt = board.moveBuffer[i].moveInt;
			board.moveBuffer[i].moveInt = temp.moveInt;
		}
	}
	else
	{
		best = board.whiteHeuristics[getFrom(board.moveBuffer[i])][getTosq(board.moveBuffer[i])];
		j = i;
		for (k = i + 1; k < board.moveBufLen[ply+1]; k++)
		{
			if (board.whiteHeuristics[getFrom(board.moveBuffer[k])][getTosq(board.moveBuffer[k])] > best)
			{
				best = board.whiteHeuristics[getFrom(board.moveBuffer[k])][getTosq(board.moveBuffer[k])];
				j = k;
			}
		}
		if (j > i)
		{
			temp.moveInt = board.moveBuffer[j].moveInt;
			board.moveBuffer[j].moveInt = board.moveBuffer[i].moveInt;
			board.moveBuffer[i].moveInt = temp.moveInt;
		}
	}

	return;
}



// start the timer
void initTimer(TIMER *timer)
{
	if (!timer->running)
	{
		timer->running = TRUE;
		ftime(&timer->startBuffer);
		timer->startTime = timer->startBuffer.time * 1000 + timer->startBuffer.millitm + timer->stopTimeDelta;
	}

	return;
}

// stop the timer
void stopTimer(TIMER *timer)
{
	if (timer->running)
	{
		timer->running = FALSE;
		ftime(&timer->stopBuffer);
		timer->stopTime = timer->stopBuffer.time * 1000 + timer->stopBuffer.millitm;
		timer->stopTimeDelta = timer->startTime - timer->stopTime;
	}

	return;
}

// reset the timer
void resetTimer(TIMER *timer)
{
	if (timer->running)
	{
		ftime(&timer->startBuffer);
		timer->startTime = timer->startBuffer.time * 1000 + timer->startBuffer.millitm;
	}
	else
	{
		timer->startTime = timer->stopTime;
		timer->stopTimeDelta = 0;
	}

	return;
}

// display time in seconds with 2 decimals
void displayTimer(TIMER *timer)
{
	if (timer->running)
	{
		ftime(&timer->currentBuffer);
		timer->currentTime = timer->currentBuffer.time * 1000 + timer->currentBuffer.millitm;
		printf("%6.2f", (timer->currentTime - timer->startTime)/1000.0);
	}
	else
		printf("%6.2f", (timer->stopTime - timer->startTime)/1000.0);

	return;
}

// display time in hh:mm:ss.dd
void displayTimerHMS(TIMER *timer)
{
	int hh, mm, ss;
	if (timer->running)
	{
		ftime(&timer->currentBuffer);
		timer->currentTime = timer->currentBuffer.time * 1000 + timer->currentBuffer.millitm;
		hh = (timer->currentTime - timer->startTime)/1000/3600;
		mm = ((timer->currentTime - timer->startTime)-hh*3600000)/1000/60;
		ss = ((timer->currentTime - timer->startTime)-hh*3600000-mm*60000)/1000;
		printf("%02d:%02d:%02d", hh, mm, ss);
	}
	else
	{
		hh = (timer->stopTime - timer->startTime)/1000/3600;
		mm = ((timer->stopTime - timer->startTime)-hh*3600000)/1000/60;
		ss = ((timer->stopTime - timer->startTime)-hh*3600000-mm*60000)/1000;
		printf("%02d:%02d:%02d", hh, mm, ss);
	}

	return;
}

// return time in milliseconds
U64 getMSTimer(TIMER *timer)
{
	if (timer->running)
	{
		ftime(&timer->currentBuffer);
		timer->currentTime = timer->currentBuffer.time * 1000 + timer->currentBuffer.millitm;
		return (timer->currentTime - timer->startTime) ;
	}
	else
		return (timer->stopTime - timer->startTime);
}

// return system time
U64 getSysMSTimer(TIMER *timer)
{
	ftime(&timer->currentBuffer);
	return (timer->currentBuffer.time * 1000 + timer->currentBuffer.millitm);
}

int qsearch(int ply, int alpha, int beta)
{
	// quiescence search

	int i, j, val;

	if (board.timedout)
		return 0;

	board.triangularLength[ply] = ply;

	// The side to move is in check - in this case the normal full width search is called, with a depth of 1.
	// This is done to ensure that all moves are generated that could evade the check (not just capturing moves).
	if (isOwnKingAttacked())
		return alphabetapvs(ply, 1, alpha, beta);

	val = eval();

	if (val >= beta)
		return val;

	if (val > alpha)
		alpha = val;

	// generate captures & promotions:
	// captgen returns a sorted move list
	board.moveBufLen[ply+1] = captgen(board.moveBufLen[ply]);
	for (i = board.moveBufLen[ply]; i < board.moveBufLen[ply+1]; i++)
	{
		makeMove(board.moveBuffer[i]);
		{
			if (isTwoKingsFaceToFace() || isOtherKingAttacked())
				unMakeMove(board.moveBuffer[i]);
			else
			{
				board.inodes++;

				if (--board.countdown <= 0)
					readClockAndInput();

				val = -qsearch(ply+1, -beta, -alpha);
				unMakeMove(board.moveBuffer[i]);
				if (val >= beta) return val;
				if (val > alpha)
				{
					alpha = val;
					board.triangularArray[ply][ply] = board.moveBuffer[i];
					for (j = ply + 1; j < board.triangularLength[ply+1]; j++)
					{
						board.triangularArray[ply][j] = board.triangularArray[ply+1][j];
					}
					board.triangularLength[ply] = board.triangularLength[ply+1];
				}
			}
		}
	}

	return alpha;
}

void mstostring(U64 dt, char *timestring)
{

	// convert milliseconds to a time string (hh:mm:ss, mm:ss, s, ms)

	U64 hh, mm, ss;

	if (dt > 3600000)
	{
		hh = dt/3600000;
		mm = (dt - 3600000*hh)/60000;
		ss = (dt - 3600000*hh - 60000*mm)/1000;

		sprintf(timestring, "%02"PRINTF_INT64_MODIFIER"u:%02"PRINTF_INT64_MODIFIER"u:%02"PRINTF_INT64_MODIFIER"u ", hh, mm, ss);
	}
	else if (dt > 60000)
	{
		mm = dt/60000;
		ss = (dt - 60000*mm)/1000;

		sprintf(timestring, "   %02"PRINTF_INT64_MODIFIER"u:%02"PRINTF_INT64_MODIFIER"u ", mm, ss);
	}
	else if (dt > 10000)
		sprintf(timestring, " %6.1f%c ", dt/1000.0, 's');
	else if (dt > 1000)
		sprintf(timestring, " %6.2f%c ", dt/1000.0, 's');
	else if (dt > 0)
		sprintf(timestring, " %5"PRINTF_INT64_MODIFIER"u%s ", dt, "ms");
	else
		sprintf(timestring, "     0%s ", "ms");

	return;

}

void readClockAndInput()
{
	// check if we need to stop, because time is up, or because the user has hit the keyboard.
	// UPDATEINTERVAL defines how often this check is done in terms of nodes searched.
	// For example, if the search speed is 1000 knods per second, then a value of UPDATEINTERVAL = 100000
	// will result in 10 checks per second (or 0.1s time intervals)

	board.countdown = UPDATEINTERVAL;
	if (getMSTimer(&board.timer)- board.msStart > board.maxTime)
	{
		board.timedout = TRUE;
		return;
	}
	return;
}


void readIniFile()
{
	int nextc;
	FILE* inifile;

	//     ===========================================================================
	//     Open the ini file:
	//     ===========================================================================
	inifile = fopen(INIFILE, "r");
	if (!inifile)
	{
		printf("warning: no ini file %s\n", INIFILE);
		printf("path: %s\n", PATHNAME);
		return;
	}
	else
	{
		printf("Initialization file: %s\n", INIFILE);
	}

	while ((nextc = getc(inifile)) != EOF)
	{
		if (nextc == '\n')
		{
			CMD_BUFF[CMD_BUFF_COUNT] = '\0';
			CMD_BUFF_COUNT = 0;
			if (!doIniCommand(CMD_BUFF)) break;
		}
		else
		{
			if (CMD_BUFF_COUNT >= MAX_CMD_BUFF-1)
			{
				printf("Warning: command buffer full !! \n");
				CMD_BUFF_COUNT = 0;
			}
			CMD_BUFF[CMD_BUFF_COUNT++] = nextc;
		}
	}
	fclose(inifile);
	return;
}

void commands()
{
	// ================================================================
	// commands is used to read console input and execute the commands
	// It also serves as winboard driver.
	// The code is based on H.G. Muller's model WinBoard protocol driver:
	// http://www.open-aurec.com/wbforum/viewtopic.php?f=24&t=51739
	// =================================================================
	int i, j, number;
	int fenhalfmoveclock;
	int fenfullmovenumber;
	char fen[100];
	char fencolor[1];
	char fencastling[4];
	char fenenpassant[2];
	//	       char sanMove[12];
	char command[80];
	char userinput[80];
	U64 msStart,msStop, perftcount;
	TIMER timer;
	MOVE move, dummy;

	// =================================================================
	// infinite loop:
	// =================================================================
	while (1)
	{

		fflush(stdout);

		// =================================================================
		// think & move
		// =================================================================
		if (XB_MODE)
		{
			if (XB_COMPUTER_SIDE == board.nextMove)
			{
				#ifdef WINGLET_DEBUG_WINBOARD
				printf("#-winglet : start think\n");
				#endif
				move = think();
				#ifdef WINGLET_DEBUG_WINBOARD
				printf("#-winglet : exit think\n");
				printf("#<winglet : move %s%s\n", SQUARENAME[getFrom(move)], SQUARENAME[getTosq(move)]);
				#endif
				if (move.moveInt)
				{
					printf("move ");
					printf("%s", SQUARENAME[getFrom(move)]);
					printf("%s",SQUARENAME[getTosq(move)]);

					//	                                  if (move.isPromotion()) printf("%s",PIECECHARS[move.getProm()]);
					printf("\n");
					makeMove(move);
					board.endOfGame++;
					board.endOfSearch = board.endOfGame;
				}
			}
			fflush(stdout);

			// =================================================================
			// ponder
			// =================================================================
			if (XB_COMPUTER_SIDE != XB_NONE && XB_COMPUTER_SIDE != XB_ANALYZE && XB_PONDER && board.endOfGame)
			{
				XB_NO_TIME_LIMIT = TRUE;
				#ifdef WINGLET_DEBUG_WINBOARD
				printf("#-winglet : start ponder\n");
				#endif
				move = think();
				#ifdef WINGLET_DEBUG_WINBOARD
				printf("#-winglet : exit ponder\n");
				#endif
				XB_NO_TIME_LIMIT = FALSE;
			}

			// =================================================================
			// analyze
			// =================================================================
			if (XB_COMPUTER_SIDE == XB_ANALYZE)
			{
				XB_NO_TIME_LIMIT = TRUE;
				#ifdef WINGLET_DEBUG_WINBOARD
				printf("#-winglet : start analyze\n");
				#endif
				move = think();
				#ifdef WINGLET_DEBUG_WINBOARD
				printf("#-winglet : exit analyze\n");
				#endif
				XB_NO_TIME_LIMIT = FALSE;
			}
		}

		noPonder:

		// =================================================================
		// display the command prompt
		// =================================================================
		if (!XB_MODE)
		{
			if (board.nextMove == WHITE_MOVE) printf("wt> ");
			else printf("bl> ");
			fflush(stdout);
		}

		// =================================================================
		// read input, but only after attending a pending command received during
		// search/ponder/analyze:
		// =================================================================
		if (!XB_DO_PENDING)
		{
			#ifdef WINGLET_DEBUG_WINBOARD
			if (XB_MODE)
				printf("#-winglet : COMPUTER_SIDE=%d PONDER=%d nextMove=%d\n", (int)XB_COMPUTER_SIDE, XB_PONDER, (int)board.nextMove);
			#endif

			for (CMD_BUFF_COUNT = 0; (CMD_BUFF[CMD_BUFF_COUNT] = getchar()) != '\n'; CMD_BUFF_COUNT++);
			CMD_BUFF[CMD_BUFF_COUNT+1] = '\0';

			#ifdef WINGLET_DEBUG_WINBOARD
			if (XB_MODE)
				printf("#>winglet : %s\n", CMD_BUFF);
			#endif
		}
		#ifdef WINGLET_DEBUG_WINBOARD
		else
		{
			if (XB_MODE)
				printf("#>winglet : %s (from peek)\n", CMD_BUFF);
		}
		#endif
		XB_DO_PENDING = FALSE;

		// =================================================================
		// ignore empty lines
		// =================================================================
		if (!CMD_BUFF_COUNT) continue;

		// =================================================================
		// extract the first word
		// =================================================================
		sscanf(CMD_BUFF, "%s", command);

		// =================================================================
		// help, h or ?: show this help - list of CONSOLE-ONLY COMMANDS
		// =================================================================
		if ((!XB_MODE) && ((!strcmp(command, "help")) || (!strcmp(command, "h")) || (!strcmp(command, "?"))))
		{
			printf("\nhelp:\n");
			printf("black               : BLACK to move\n");
			printf("cc                  : play computer-to-computer \n");
			printf("d                   : display board \n");
			printf("eval                : show static evaluation of this position\n");
			printf("exit                : exit program \n");
			printf("game                : show game moves \n");
			printf("go                  : computer next move \n");
			printf("help, h, or ?       : show this help \n");
			printf("info                : display variables (for testing purposes)\n");
			printf("ini                 : read the initialization file\n");
			printf("memory n            : max memory to use (in MB)\n");
			printf("move e2e4, or h7h8q : enter a move (use this format)\n");
			printf("moves               : show all legal moves\n");
			printf("new                 : start new game\n");
			printf("perft n             : calculate raw number of nodes from here, depth n \n");
			#ifdef WINGLET_VERBOSE_SEE
			printf("qsearch             : shows sorted capture movelist\n");
			#endif
			printf("quit                : exit program \n");
			printf("r                   : rotate board \n");
			printf("readfen filename n  : reads #-th FEN position from filename\n");
			printf("sd n                : set the search depth to n\n");
			printf("setup               : setup board... \n");
			printf("test filename       : starts search on all FEN position in 'filename'\n");
			printf("                      using current time & search depth parameters\n");
			printf("                      output is written in test.log\n");
			printf("time s              : time per move in seconds\n");
			printf("undo                : take back last move\n");
			printf("white               : WHITE to move\n");
			printf("\n");
			continue;
		}

		// =================================================================
		// accepted: in reply to the "feature" command
		// =================================================================
		if (XB_MODE && !strcmp(command, "accepted"))
			continue;

		// =================================================================
		// analyze: enter analyze mode
		// =================================================================
		if (XB_MODE && !strcmp(command, "analyze"))
		{
			XB_COMPUTER_SIDE = XB_ANALYZE;
			continue;
		}

		// =================================================================
		// black: BLACK to move
		// =================================================================
		if (!XB_MODE && !strcmp(command, "black") && board.nextMove == WHITE_MOVE)
		{
			//	                     board.hashkey ^= KEY.side;
			board.endOfSearch = 0;
			board.endOfGame = 0;
			board.nextMove = BLACK_MOVE;
			continue;
		}

		// =================================================================
		// bk: show book moves from this position, if any
		// =================================================================
		if (XB_MODE && !strcmp(command, "bk"))
			continue;

		// =================================================================
		// cc: play computer-to-computer
		// =================================================================
		if (!XB_MODE && !strcmp(command, "cc"))
		{
			while (!isEndOfgame(&i, &dummy))
			{
				move = think();
				if (move.moveInt)
				{
					makeMove(move);
					board.endOfGame++;
					board.endOfSearch = board.endOfGame;
					displayBoard(board);
				}
			}
			continue;
		}

		// =================================================================
		// computer: the opponent is also a computer chess engine
		// =================================================================
		if (XB_MODE && !strcmp(command, "computer"))
			continue;

		// =================================================================
		// cores n: informs the engine on how many CPU cores it is allowed to use maximally
		// =================================================================
		if (XB_MODE && !strcmp(command, "cores"))
			continue;

		// =================================================================
		// d: display board
		// =================================================================
		if (!XB_MODE && !strcmp(command, "d"))
		{
			displayBoard(board);
			continue;
		}

		// =================================================================
		// easy: turn off pondering
		// =================================================================
		if (XB_MODE && !strcmp(command, "easy"))
		{
			XB_PONDER = FALSE;
			continue;
		}

		// =================================================================
		// egtpath type path: informs the engine in which directory it can find end-game tables
		// =================================================================
		if (XB_MODE && !strcmp(command, "egtpath"))
			continue;

		// =================================================================
		// eval: show static evaluation of this position
		// =================================================================
		if (!XB_MODE && !strcmp(command, "eval"))
		{
			number = eval();
			printf("eval score = %d\n", number);
			continue;
		}

		// =================================================================
		// exit: leave analyze mode / exit program (if not in WB)
		// =================================================================
		if (!strcmp(command, "exit"))
		{
			if (XB_MODE)
			{
				XB_COMPUTER_SIDE = XB_NONE;
				continue;
			}
			else break;
		}

		// =================================================================
		// force: Set the engine to play neither color
		// =================================================================
		if (XB_MODE && !strcmp(command, "force"))
		{
			XB_COMPUTER_SIDE = XB_NONE;
			continue;
		}

		// =================================================================
		// game: show game moves
		// =================================================================
		if (!XB_MODE && !strcmp(command, "game"))
		{
			if (board.endOfGame)
			{
				// make a temporary copy of board.gameLine[];
				number = board.endOfGame;
				GAMELINERECORD tmp[number];
				memcpy(tmp, board.gameLine, number * sizeof(GAMELINERECORD));

				// unmake all moves:
				for (i = number-1 ; i >= 0 ; i--)
				{
					unMakeMove(tmp[i].move);
					board.endOfSearch = --board.endOfGame;
				}

				// redo all moves:
				j = board.nextMove;
				for (i = 0 ; i < number; i++)
				{
					// move numbering:
					if (!((i+j+2)%2))
						printf("%d. ", (i+2*j+2)/2);
					else if (!i)
						printf("1. ... ");

					// construct the move string
					//	                                  toSan(tmp[i].move, sanMove);
					//	                                  printf(sanMove;
					displayMove(tmp[i].move);

					// output CRLF, or space:
					if (!((i+j+1)%2))
						printf("\n");
					else
						printf(" ");

					// make the move:
					makeMove(tmp[i].move);
					board.endOfSearch = ++board.endOfGame;
				}
				printf("\n");

				// delete the temporary copy:
				//	                           delete[] tmp;
			}
			else
			{
				printf("there are no game moves\n");
			}
			continue;
		}

		// =================================================================
		// go: leave force mode and set the engine to play the color that is on move
		// =================================================================
		if (!strcmp(command, "go"))
		{
			if (XB_MODE)
			{
				XB_COMPUTER_SIDE = board.nextMove;
				continue;
			}
			else
			{
				if (!isEndOfgame(&i, &dummy))
				{
					move = think();
					if (move.moveInt)
					{
						makeMove(move);
						board.endOfGame++;
						board.endOfSearch = board.endOfGame;
					}
					displayBoard(board);
					isEndOfgame(&i, &dummy);
					CMD_BUFF_COUNT = 0;
				}
				else
				{
					displayBoard(board);
					CMD_BUFF_COUNT = 0;
				}
			}
			continue;
		}

		// =================================================================
		// hard: turn on pondering
		// =================================================================
		if (XB_MODE && !strcmp(command, "hard"))
		{
			XB_PONDER = TRUE;
			continue;
		}

		// =================================================================
		// hint: respond with "Hint: xxx", where xxx is a suggested move
		// =================================================================
		if (XB_MODE && !strcmp(command, "hint"))
			continue;

		// =================================================================
		// ics hostname: the engine is playing on an Internet Chess Server (ICS) with the given hostname
		// =================================================================

		if (XB_MODE && !strcmp(command, "ics"))
			continue;

		// =================================================================
		// info: display variables (for testing purposes)
		// =================================================================
		if (!XB_MODE && !strcmp(command, "info"))
			continue;

		// =================================================================
		// ini: read the initialization file
		// =================================================================
		if (!XB_MODE && !strcmp(command, "ini"))
		{
			readIniFile();
			continue;
		}

		// =================================================================
		// level mps base inc: set time controls
		// =================================================================
		if (XB_MODE && !strcmp(command, "level"))
		{
			//	                     sscanf(CMD_BUFF, "level %d %d %d", &XB_MPS, &XB_MIN, &XB_INC) == 3 ||
			//	                     sscanf(CMD_BUFF, "level %d %d:%d %d", &XB_MPS, &XB_MIN, &XB_SEC, &XB_INC);
			//	                     XB_INC *= 1000;
			continue;
		}

		// =================================================================
		// memory n: informs the engine on how much memory it is allowed to use maximally, in MB
		// =================================================================

		if (XB_MODE && !strcmp(command, "memory"))
			continue;

		// =================================================================
		// moves: show all legal moves
		// =================================================================

		if (!XB_MODE && !strcmp(command, "moves"))
		{
			board.moveBufLen[0] = 0;
			board.moveBufLen[1] = movegen(board.moveBufLen[0]);
			printf("\nmoves from this position:\n");
			number = 0;
			for (i = board.moveBufLen[0]; i < board.moveBufLen[1]; i++)
			{
				makeMove(board.moveBuffer[i]);
				if (isOtherKingAttacked())
				{
					unMakeMove(board.moveBuffer[i]);
				}
				else
				{
					unMakeMove(board.moveBuffer[i]);
					//	                                  toSan(board.moveBuffer[i], sanMove);
					printf("%d. ", ++number);
					displayMove(board.moveBuffer[i]);
				}
			}
			continue;
		}

		// =================================================================
		// move: enter a move (use this format: move e2e4, or h7h8q)
		// =================================================================
		if (!XB_MODE && !strcmp(command, "move"))
		{
			sscanf(CMD_BUFF, "move %s", userinput);
			// generate the pseudo-legal move list
			board.moveBufLen[0] = 0;
			board.moveBufLen[1] = movegen(board.moveBufLen[0]);

			if (isValidTextMove(userinput, &move))        // check to see if the user move is also found in the pseudo-legal move list
			{
				makeMove(move);

				if (isOtherKingAttacked())              // post-move check to see if we are leaving our king in check
				{
					unMakeMove(move);
					printf("    invalid move, leaving king in check: %s\n", userinput);
				}
				else
				{
					board.endOfGame++;
					board.endOfSearch = board.endOfGame;
					displayBoard(board);
				}
			}
			else
			{
				printf("    move is invalid or not recognized: %s\n", userinput);
			}
			continue;
		}

		// =================================================================
		// name <something>: informs the engine of its opponent's name
		// =================================================================

		if (XB_MODE && !strcmp(command, "name")) continue;

		// =================================================================
		// new: reset the board to the standard chess starting position
		// =================================================================

		if (!strcmp(command, "new"))
		{
			initBoard(&board);
			if (XB_MODE)
			{
				XB_COMPUTER_SIDE = BLACK_MOVE;
				board.searchDepth = MAX_PLY;
			}
			continue;
		}

		// =================================================================
		// nopost: turn off thinking/pondering output
		// =================================================================

		if (XB_MODE && !strcmp(command, "nopost"))
		{
			XB_POST = FALSE;
			continue;
		}

		// =================================================================
		// otim n: set a clock that belongs to the opponent, in centiseconds
		// =================================================================
		if (XB_MODE && !strcmp(command, "otim"))
		{
			// do not start pondering after receiving time commands, as a move will follow immediately
			sscanf(CMD_BUFF, "otim %d", &XB_OTIM);
			XB_OTIM *= 10;  // convert to miliseconds;
			goto noPonder;
		}

		// =================================================================
		// option name[=value]: setting of an engine-define option
		// =================================================================
		if (XB_MODE && !strcmp(command, "option"))  continue;

		// =================================================================
		// perft: calculate raw number of nodes from here, depth n
		// =================================================================
		if (!XB_MODE && !strcmp(command, "perft"))
		{
			sscanf(CMD_BUFF,"perft %d", &number);
			printf("    starting perft %d...\n", number);
			initTimer(&timer);
			board.moveBufLen[0] = 0;

			msStart = getMSTimer(&timer);
			perftcount = perft(0, number);
			msStop = getMSTimer(&timer);

			printf("nodes        = %"PRINTF_INT64_MODIFIER"u, %"PRINTF_INT64_MODIFIER"u ms, ", perftcount, msStop - msStart);
			if ((msStop - msStart) > 0)
				printf("%"PRINTF_INT64_MODIFIER"u knods/s", (perftcount/(msStop - msStart)));
			printf("\n");
			CMD_BUFF_COUNT = 0;

			continue;
		}

		// =================================================================
		// ping n: reply by sending the string pong n
		// =================================================================
		if (XB_MODE && !strcmp(command, "ping"))
		{
			sscanf(CMD_BUFF,"ping %d", &number);
			printf("pong %d\n", number);
			continue;
		}

		// =================================================================
		// post: turn on thinking/pondering output
		// =================================================================
		if (XB_MODE && !strcmp(command, "post"))
		{
			XB_POST = TRUE;
			continue;
		}

		// =================================================================
		// protover n: protocol version
		// =================================================================
		if (XB_MODE && !strcmp(command, "protover"))
		{
			printf("feature ping=1\n");
			printf("feature setboard=1\n");
			printf("feature colors=0\n");
			printf("feature usermove=1\n");
			printf("feature memory=1\n");
			printf("feature debug=1\n");
			printf("feature done=1\n");

			continue;
		}

		// =================================================================
		// quit: exit program
		// =================================================================
		if (!strcmp(command, "quit"))
			break;

		// =================================================================
		// r: rotate board
		// =================================================================

		if (!XB_MODE && !strcmp(command, "r"))
		{
			board.viewRotated = !board.viewRotated;
			continue;
		}

		// =================================================================
		// random: ignored
		// =================================================================
		if (XB_MODE && !strcmp(command, "random"))
			continue;

		// =================================================================
		// rating: ICS opponent's rating
		// =================================================================
		if (XB_MODE && !strcmp(command, "rating"))
			continue;

		// =================================================================
		// readfen filename n: reads #-th FEN position from filename
		// =================================================================
		if (!XB_MODE && !strcmp(command, "readfen"))
		{
			sscanf(CMD_BUFF,"readfen %s %d", userinput, &number);
			initBoard(&board);
			//	                     readFen(userinput, number);
			displayBoard(board);
			continue;
		}

		// =================================================================
		// rejected: feature is rejected
		// =================================================================
		if (XB_MODE && !strcmp(command, "rejected"))
			continue;

		// =================================================================
		// remove: undo the last two moves (one for each player) and continue playing the same color.
		// =================================================================
		if (XB_MODE && !strcmp(command, "remove"))
		{
			if (board.endOfGame)
			{
				unMakeMove(board.gameLine[--board.endOfGame].move);
				board.endOfSearch = board.endOfGame;
			}
			if (board.endOfGame)
			{
				unMakeMove(board.gameLine[--board.endOfGame].move);
				board.endOfSearch = board.endOfGame;
			}
			continue;
		}

		// =================================================================
		// result string {comment}: end the each game, e.g.: result 1-0 {White mates}
		// =================================================================
		if (XB_MODE && !strcmp(command, "result"))
		{
			XB_COMPUTER_SIDE = XB_NONE;
			continue;
		}

		// =================================================================
		// sd n: set the search depth to n
		// =================================================================

		if (!strcmp(command, "sd"))
		{
			sscanf(CMD_BUFF,"sd %d", &board.searchDepth);
			if (board.searchDepth < 1) board.searchDepth = 1;
			if (board.searchDepth > MAX_PLY) board.searchDepth = MAX_PLY;
			printf("winglet> search depth %d\n", board.searchDepth);
			continue;
		}

		// =================================================================
		// setboard fen: set up the board/position
		// =================================================================
		if (XB_MODE && !strcmp(command, "setboard"))
		{
			XB_COMPUTER_SIDE = XB_NONE;
			sscanf(CMD_BUFF, "setboard %s %s %s %s %d %d", fen, fencolor, fencastling, fenenpassant, &fenhalfmoveclock, &fenfullmovenumber);
			//	                     setupFen(fen, fencolor, fencastling, fenenpassant, fenhalfmoveclock, fenfullmovenumber);
			continue;
		}

		// =================================================================
		// setup: setup board...
		// =================================================================

		if (!XB_MODE && !strcmp(command, "setup"))
		{
			//	                     setup();
			continue;
		}

		// =================================================================
		// stopfrac (0-100%): undocumented command to interactively change this
		// parameter (e.g. for running testsuites), default value is 60
		// Don't start a new iteration if STOPFRAC fraction of the max search time
		// has passed
		// =================================================================

		if (!XB_MODE && !strcmp(command, "stopfrac"))
		{
			number = (int)(STOPFRAC * 100);
			sscanf(CMD_BUFF, "stopfrac %d", &number);
			if (number < 1) number = 1;
			if (number > 100) number = 100;
			STOPFRAC = (float)(number/100.0);
			printf("winglet> stopfrac %f\n", 100*STOPFRAC);
			continue;
		}

		// =================================================================
		// st time: set time controls
		// =================================================================

		if (XB_MODE && !strcmp(command, "st"))
		{
			sscanf(CMD_BUFF, "st %"PRINTF_INT64_MODIFIER"u", &board.maxTime);
			board.maxTime *= board.maxTime;  // convert to ms
			continue;
		}

		// =================================================================
		// test filename: starts search on all FEN position in 'filename
		// =================================================================

		if (!XB_MODE && !strcmp(command, "test"))
		{
			sscanf(CMD_BUFF,"test %s", userinput);
			initBoard(&board);
			//	                     test(userinput);
			continue;
		}

		// =================================================================
		// time: set a clock that belongs to the engine
		// =================================================================

		if (!strcmp(command, "time"))
		{
			number = (int)board.maxTime / 1000;
			sscanf(CMD_BUFF,"time %d", &number);
			if (number < 1) number = 1;
			if (!XB_MODE) printf("winglet> search time %d seconds\n", number);
			if (XB_MODE)
			{
				XB_CTIM = number * 10;
				board.maxTime = number * 10; // conversion to ms
			}
			else
			{
				board.maxTime = number * 1000; // conversion to ms
			}
			goto noPonder;
		}

		// =================================================================
		// undo: take back last move
		// =================================================================

		if (!strcmp(command, "undo"))
		{
			if (board.endOfGame)
			{
				unMakeMove(board.gameLine[--board.endOfGame].move);
				board.endOfSearch = board.endOfGame;
				if (!XB_MODE) displayBoard(board);
			}
			else if (!XB_MODE) printf("already at start of game\n");
			continue;
		}

		// =================================================================
		// usermove move: do a move
		// =================================================================

		if (XB_MODE && !strcmp(command, "usermove"))
		{
			sscanf(CMD_BUFF,"usermove %s",userinput);

			// generate the pseudo-legal move list
			board.moveBufLen[0] = 0;
			board.moveBufLen[1] = movegen(board.moveBufLen[0]);

			if (isValidTextMove(userinput, &move))        // check to see if the user move is also found in the pseudo-legal move list
			{
				makeMove(move);
				if (isOtherKingAttacked())              // post-move check to see if we are leaving our king in check
				{
					#ifdef WINGLET_DEBUG_WINBOARD
					printf("#-winglet : usermove illegal\n");
					#endif
					unMakeMove(move);
				}
				else
				{
					#ifdef WINGLET_DEBUG_WINBOARD
					printf("#-winglet : usermove %s made\n", userinput);
					#endif
					board.endOfGame++;
					board.endOfSearch = board.endOfGame;
				}
			}
			else
			{
				#ifdef WINGLET_DEBUG_WINBOARD
				printf("#-winglet : usermove illegal\n");
				#endif
			}
			continue;
		}

		// =================================================================
		// variant: the game is not standard chess
		// =================================================================

		if(XB_MODE && !strcmp(command, "variant")) continue;

		// =================================================================
		// white: WHITE to move
		// =================================================================

		if (!XB_MODE && !strcmp(command, "white") && board.nextMove == BLACK_MOVE)
		{
			//	                     board.hashkey ^= KEY.side;
			board.endOfSearch = 0;
			board.endOfGame = 0;
			board.nextMove = WHITE_MOVE;
			continue;
		}

		// =================================================================
		// xboard: put the engine into "xboard mode", stop all unsolicited output
		// =================================================================

		if (!XB_MODE && !strcmp(command, "xboard"))
		{
			#ifdef WINGLET_DEBUG_WINBOARD
			if (XB_MODE)
				printf("#>winglet : xboard\n");
			#endif

			printf("\n");
			XB_COMPUTER_SIDE = XB_NONE;
			XB_MODE = TRUE;
			XB_POST = FALSE;
			initBoard(&board);
			continue;
		}

		// =================================================================
		// unknown command:
		// =================================================================

		printf("Error: unknown command: %s\n", command);
		#ifdef WINGLET_DEBUG_WINBOARD
		if (XB_MODE)
			printf("#<winglet : Error: unknown command: %s\n", command);
		#endif
	}
}

BOOL doIniCommand(const char *buf)
{
	int number;

	if (!strncmp(buf, "depth", 5))
	{
		sscanf(buf+5, "%d", &board.searchDepth);
		if (board.searchDepth < 1) board.searchDepth = 1;
		if (board.searchDepth > MAX_PLY) board.searchDepth = MAX_PLY;
		CMD_BUFF_COUNT = 0;
		return TRUE;
	}

	if (!strncmp(buf, "time", 4))
	{
		sscanf(buf+4,"%"PRINTF_INT64_MODIFIER"u",&board.maxTime);
		board.maxTime *= 1000;  // convert to milliseconds
		if (board.maxTime < 0) board.maxTime = 1;
		CMD_BUFF_COUNT = 0;
		return TRUE;
	}

	if (!strncmp(buf, "STOP_FRAC", 9))
	{
		sscanf(buf+9, "%d", &number);
		STOPFRAC = (float)(number/100.0);
		CMD_BUFF_COUNT = 0;
		return TRUE;
	}

	return TRUE;
}
